├── test.txt ├── clib ├── include │ ├── math.h │ ├── time.h │ ├── errno.h │ ├── stdbool.h │ ├── stdarg.h │ ├── stddef.h │ ├── stdint.h │ ├── stdlib.h │ ├── limits.h │ ├── assert.h │ ├── string.h │ ├── ctype.h │ ├── stdio.h │ ├── liballoc.h │ └── string386.inl ├── assert.cpp ├── ctype.c ├── internal_file.h ├── string.asm ├── stdlib.cpp └── string.c ├── test.elf ├── boot ├── gdt.asm ├── multiboot.asm ├── memmap.asm ├── disk.asm ├── fatload.asm └── boot_sect.asm ├── fonts ├── font08.psf └── font16.psf ├── readme.txt ├── drivers ├── at_kbrd.h ├── display │ ├── vesa │ │ └── sys │ │ │ └── io.h │ └── basic_text │ │ ├── basic_text.h │ │ └── basic_text.cpp ├── ramdisk.h ├── formats │ ├── rdfs.h │ ├── mbr.cpp │ └── rdfs.cpp ├── cpu │ ├── lapic.h │ ├── ap_bootstrap.asm │ ├── madt.cpp │ └── lapic.cpp ├── pit.h ├── portio.asm ├── driver.ld ├── cmos.h ├── isa_dma.h ├── rs232.h ├── pci.h ├── rs232.c ├── ramdisk.cpp ├── ata_cmd.h ├── pit.cpp ├── portio.h ├── ps2mouse.cpp └── cmos.cpp ├── kernel ├── bootstrap │ ├── entry.asm │ ├── boot_info.h │ ├── boot_mapper.cpp │ └── boot_info.c ├── kassert.h ├── syscall.h ├── cpu.h ├── sections.h ├── driver.h ├── screen.asm ├── driver_loader.h ├── filesystem │ ├── drives.h │ ├── util.h │ └── fs_driver.h ├── rt_device.cpp ├── input.h ├── shared_mem.h ├── physical_manager.h ├── rt_device.h ├── sys │ └── syscalls.h ├── sysclock.h ├── syscall.asm ├── dynamic_object.h ├── multiboot.h ├── task.h ├── interrupt.asm ├── display.h ├── interrupt.h ├── input.cpp ├── syscall.c ├── sysclock.cpp ├── shared_mem.cpp ├── tss.h ├── gdt.cpp ├── memorymanager.h ├── locks.cpp ├── task.asm ├── util │ └── hash.h └── kernel.c ├── libclang_rt.builtins-i386.a ├── configs ├── cdboot │ ├── init.sys │ ├── cdboot.sys │ └── meson.build ├── fdboot │ ├── init.sys │ ├── fdboot.sys │ └── meson.build └── netboot │ ├── init.sys │ └── meson.build ├── .editorconfig ├── .gitignore ├── limine.cfg ├── api ├── keyboard.h ├── crtn.asm ├── thread.h ├── crti.asm ├── files.h ├── keyboard.c ├── virtual_keys.h ├── thread.cpp ├── terminal │ └── terminal.h └── crt0.c ├── .gitmodules ├── tools ├── meson.build ├── buildiso.pl └── rdfs.cpp ├── cpplib ├── include │ ├── functional │ ├── new │ ├── atomic │ ├── charconv │ ├── bit │ ├── utility │ ├── char_traits.h │ ├── array │ └── iterator └── cppruntime.cpp ├── shell ├── commands.h ├── shell.h └── util.h ├── CppProperties.json ├── common ├── input_event.h ├── task_data.h ├── display_mode.h └── util.h ├── apps ├── fwrite.cpp ├── bkgrnd.cpp ├── primes.cpp ├── listmode.cpp ├── threads.cpp ├── graphics.cpp └── init.cpp ├── test.bat ├── mesoncross.ini ├── .github └── workflows │ └── build.yml ├── CONTRIBUTING.md ├── linker.ld ├── LICENSE.txt ├── .clang-format └── README.md /test.txt: -------------------------------------------------------------------------------- 1 | test rs232 1550948933 -------------------------------------------------------------------------------- /clib/include/math.h: -------------------------------------------------------------------------------- 1 | #ifndef MATH_H 2 | #define MATH_H 3 | 4 | #endif -------------------------------------------------------------------------------- /test.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgrAm/JSD-OS/HEAD/test.elf -------------------------------------------------------------------------------- /boot/gdt.asm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgrAm/JSD-OS/HEAD/boot/gdt.asm -------------------------------------------------------------------------------- /fonts/font08.psf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgrAm/JSD-OS/HEAD/fonts/font08.psf -------------------------------------------------------------------------------- /fonts/font16.psf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgrAm/JSD-OS/HEAD/fonts/font16.psf -------------------------------------------------------------------------------- /clib/include/time.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgrAm/JSD-OS/HEAD/clib/include/time.h -------------------------------------------------------------------------------- /readme.txt: -------------------------------------------------------------------------------- 1 | I don't know why there is a readme, just so the disk doesn't look so empty -------------------------------------------------------------------------------- /drivers/at_kbrd.h: -------------------------------------------------------------------------------- 1 | #ifndef AT_KBRD_H 2 | #define AT_KBRD_H 3 | void AT_keyboard_init(); 4 | #endif -------------------------------------------------------------------------------- /kernel/bootstrap/entry.asm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgrAm/JSD-OS/HEAD/kernel/bootstrap/entry.asm -------------------------------------------------------------------------------- /libclang_rt.builtins-i386.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pgrAm/JSD-OS/HEAD/libclang_rt.builtins-i386.a -------------------------------------------------------------------------------- /configs/cdboot/init.sys: -------------------------------------------------------------------------------- 1 | load_driver at_kbrd.drv 2 | load_driver ata.drv 3 | load_driver iso9660.drv 4 | load_file cdboot.sys -------------------------------------------------------------------------------- /configs/fdboot/init.sys: -------------------------------------------------------------------------------- 1 | load_driver at_kbrd.drv 2 | load_driver floppy.drv 3 | load_driver fat.drv 4 | load_file fdboot.sys -------------------------------------------------------------------------------- /clib/include/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef ERRNO_H 2 | #define ERRNO_H 3 | 4 | static int errno = 0; 5 | 6 | #define EISDIR -1 7 | 8 | #endif -------------------------------------------------------------------------------- /kernel/kassert.h: -------------------------------------------------------------------------------- 1 | #ifndef K_ASSERT_H 2 | #define K_ASSERT_H 3 | 4 | #include 5 | #define k_assert(e) assert(e) 6 | 7 | #endif -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{cpp,c,h}] 4 | end_of_line = lf 5 | indent_style = tab 6 | indent_size = 4 7 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /configs/netboot/init.sys: -------------------------------------------------------------------------------- 1 | load_driver at_kbrd.drv 2 | load_driver vesa.drv 3 | load_driver i8042.drv 4 | load_driver ps2mouse.drv 5 | execute shell.elf -------------------------------------------------------------------------------- /drivers/display/vesa/sys/io.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_H 2 | #define IO_H 3 | 4 | #include 5 | 6 | #define inl ind 7 | #define outl outd 8 | 9 | #endif -------------------------------------------------------------------------------- /kernel/syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSCALL_H 2 | #define SYSCALL_H 3 | 4 | #define SYSCALL_HANDLER __attribute__((regcall)) 5 | 6 | void setup_syscalls(); 7 | 8 | #endif -------------------------------------------------------------------------------- /kernel/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef CPU_H 2 | #define CPU_H 3 | 4 | #include 5 | 6 | struct cpu_state 7 | { 8 | cpu_state* self = this; 9 | arch_data arch; 10 | }; 11 | 12 | #endif -------------------------------------------------------------------------------- /configs/fdboot/fdboot.sys: -------------------------------------------------------------------------------- 1 | load_driver vga.drv 2 | load_driver mbr.drv 3 | load_driver ata.drv 4 | load_driver iso9660.drv 5 | load_driver i8042.drv 6 | load_driver ps2mouse.drv 7 | execute shell.elf -------------------------------------------------------------------------------- /drivers/ramdisk.h: -------------------------------------------------------------------------------- 1 | #ifndef RAMDISK_H 2 | #define RAMDISK_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | void ramdisk_init(); 7 | #ifdef __cplusplus 8 | } 9 | #endif 10 | #endif -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | os.zip 2 | *.vfd 3 | *.exe 4 | build/* 5 | build.bat 6 | drivers/asm_output.s 7 | drivers/asm_output.s 8 | *.o 9 | *.o 10 | test.txt 11 | notes.txt 12 | /.vs 13 | /run.bat 14 | /builddir 15 | -------------------------------------------------------------------------------- /limine.cfg: -------------------------------------------------------------------------------- 1 | GRAPHICS=no 2 | 3 | :Multiboot jsd-os 4 | 5 | COMMENT=jsd-os 6 | 7 | PROTOCOL=multiboot1 8 | KERNEL_PATH=boot:///system/kernal.sys 9 | 10 | MODULE_PATH=boot:///system/init.rfs 11 | MODULE_STRING=ramdisk 12 | -------------------------------------------------------------------------------- /clib/include/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef STDBOOL_H 2 | #define STDBOOL_H 3 | 4 | #ifndef __cplusplus 5 | #define bool _Bool 6 | #define true 1 7 | #define false 0 8 | #define __bool_true_false_are_defined 1 9 | #endif 10 | 11 | #endif -------------------------------------------------------------------------------- /drivers/display/basic_text/basic_text.h: -------------------------------------------------------------------------------- 1 | #ifndef BASIC_TEXT_H 2 | #define BASIC_TEXT_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | void basic_text_init(void); 8 | 9 | #ifdef __cplusplus 10 | } 11 | #endif 12 | #endif -------------------------------------------------------------------------------- /drivers/formats/rdfs.h: -------------------------------------------------------------------------------- 1 | #ifndef RDFS_H 2 | #define RDFS_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | void rdfs_init(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | #endif -------------------------------------------------------------------------------- /api/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef KEYBOARD_H 2 | #define KEYBOARD_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | char get_ascii_from_vk(key_type k); 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | #endif -------------------------------------------------------------------------------- /drivers/cpu/lapic.h: -------------------------------------------------------------------------------- 1 | #ifndef LAPIC_H 2 | #define LAPIC_H 3 | 4 | #include 5 | 6 | struct cpu_core 7 | { 8 | size_t lapic_id; 9 | }; 10 | 11 | void init_smp(uintptr_t lapic_phys_addr, std::vector& cores); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "drivers/display/vesa/libx86emu"] 2 | path = drivers/display/vesa/libx86emu 3 | url = https://github.com/pgrAm/libx86emu.git 4 | [submodule "tools/limine"] 5 | path = tools/limine 6 | url = https://github.com/limine-bootloader/limine.git 7 | -------------------------------------------------------------------------------- /api/crtn.asm: -------------------------------------------------------------------------------- 1 | ; x86 crtn.s 2 | section .init 3 | ; clang will nicely put the contents of crtend.o's .init section here. 4 | pop ebp 5 | ret 6 | 7 | section .fini 8 | ; clang will nicely put the contents of crtend.o's .fini section here. 9 | pop ebp 10 | ret -------------------------------------------------------------------------------- /tools/meson.build: -------------------------------------------------------------------------------- 1 | rdfs = executable('rdfs', 'rdfs.cpp', cpp_args: ['-std=c++20', '-O2'], native : true) 2 | 3 | limine_deploy = executable( 4 | 'limine-deploy', 5 | ['limine/limine-deploy.c'], 6 | c_args: ['-O2', '-D_CRT_SECURE_NO_WARNINGS'], 7 | native : true 8 | ) -------------------------------------------------------------------------------- /api/thread.h: -------------------------------------------------------------------------------- 1 | #ifndef THREAD_H 2 | #define THREAD_H 3 | 4 | #include 5 | 6 | struct tls_thread_block; 7 | 8 | tls_thread_block* get_thread_ptr(); 9 | 10 | task_id spawn_thread(void (*func)()); 11 | 12 | void init_first_thread(); 13 | 14 | #endif -------------------------------------------------------------------------------- /configs/cdboot/cdboot.sys: -------------------------------------------------------------------------------- 1 | load_driver drivers/mbr.drv 2 | //load_driver drivers/floppy.drv 3 | load_driver drivers/fat.drv 4 | load_driver drivers/ext2.drv 5 | load_driver drivers/vesa.drv 6 | load_driver drivers/i8042.drv 7 | load_driver drivers/ps2mouse.drv 8 | execute shell.elf -------------------------------------------------------------------------------- /drivers/pit.h: -------------------------------------------------------------------------------- 1 | #ifndef PIT_H 2 | #define PIT_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | tick_t pit_get_tick_rate(); 11 | tick_t pit_get_ticks(); 12 | void pit_init(); 13 | 14 | #ifdef __cplusplus 15 | } 16 | #endif 17 | #endif -------------------------------------------------------------------------------- /kernel/sections.h: -------------------------------------------------------------------------------- 1 | #ifndef _SECTIONS_H 2 | #define _SECTIONS_H 3 | 4 | #define RECLAIMABLE __attribute__((section(".reclaimable_text"))) 5 | #define RECLAIMABLE_DATA __attribute__((section(".reclaimable_data"))) 6 | #define RECLAIMABLE_BSS __attribute__((section(".reclaimable_bss"))) 7 | #endif -------------------------------------------------------------------------------- /kernel/driver.h: -------------------------------------------------------------------------------- 1 | #ifndef DRIVER_H 2 | #define DRIVER_H 3 | 4 | struct directory_stream; 5 | typedef struct directory_stream directory_stream; 6 | 7 | typedef int (*driver_init_func)(directory_stream* cwd); 8 | 9 | #define EXPORT_SYM __attribute__((visibility("default"))) 10 | 11 | #endif -------------------------------------------------------------------------------- /cpplib/include/functional: -------------------------------------------------------------------------------- 1 | #ifndef STD_FUNCTIONAL_H 2 | #define STD_FUNCTIONAL_H 3 | 4 | namespace std 5 | { 6 | 7 | template 8 | struct less 9 | { 10 | constexpr bool operator()(const T& lhs, const T& rhs) const 11 | { 12 | return lhs < rhs; 13 | } 14 | }; 15 | 16 | }; 17 | #endif -------------------------------------------------------------------------------- /shell/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef SHELL_COMMANDS_H 2 | #define SHELL_COMMANDS_H 3 | 4 | #include 5 | #include 6 | 7 | struct command_result 8 | { 9 | int result; 10 | bool found; 11 | }; 12 | 13 | command_result run_command(std::string_view keyword, 14 | std::vector& args); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /api/crti.asm: -------------------------------------------------------------------------------- 1 | ; x86 crti.asm 2 | section .init 3 | global _init 4 | _init: 5 | push ebp 6 | mov ebp, esp 7 | ; clang will nicely put the contents of crtbegin.o's .init section here. 8 | 9 | section .fini 10 | global _fini 11 | _fini: 12 | push ebp 13 | mov ebp, esp 14 | ; clang will nicely put the contents of crtbegin.o's .fini section here. -------------------------------------------------------------------------------- /configs/cdboot/meson.build: -------------------------------------------------------------------------------- 1 | cdrfs = custom_target( 2 | 'cdboot_rfs', 3 | output : 'init.rfs', 4 | input : [ 5 | 'init.sys', 6 | driver_map.get('iso9660'), 7 | driver_map.get('ata'), 8 | driver_map.get('at_kbrd'), 9 | driver_map.get('pci'), 10 | init_loader, 11 | ], 12 | command : rdfs_command, 13 | build_by_default: true 14 | ) -------------------------------------------------------------------------------- /kernel/screen.asm: -------------------------------------------------------------------------------- 1 | [ bits 32] 2 | ; Define some constants 3 | VIDEOMEM equ 0xb8000 4 | 5 | asm_clear_screen: 6 | pusha 7 | 8 | mov edx, VIDEO_MEMORY 9 | mov al, 0x00 10 | clear_screen_loop: 11 | mov [edx], ax 12 | add edx, 2 13 | ;add ah, 0x10 14 | cmp edx, VIDEOMEM + 4000 ;end of screen 15 | jle clear_screen_loop 16 | popa 17 | ret 18 | -------------------------------------------------------------------------------- /clib/include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef STDARG_H 2 | #define STDARG_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | typedef __builtin_va_list va_list; 8 | 9 | #define va_start(v,l) __builtin_va_start(v,l) 10 | #define va_end(v) __builtin_va_end(v) 11 | #define va_arg(v,l) __builtin_va_arg(v,l) 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | #endif -------------------------------------------------------------------------------- /configs/fdboot/meson.build: -------------------------------------------------------------------------------- 1 | fdrfs = custom_target( 2 | 'fdboot_rfs', 3 | output : 'init.rfs', 4 | input : [ 5 | 'init.sys', 6 | driver_map.get('fat'), 7 | driver_map.get('floppy'), 8 | driver_map.get('at_kbrd'), 9 | driver_map.get('isa_dma'), 10 | init_loader, 11 | ], 12 | command : rdfs_command, 13 | build_by_default: true 14 | ) -------------------------------------------------------------------------------- /kernel/driver_loader.h: -------------------------------------------------------------------------------- 1 | #ifndef DRIVER_LOADER_H 2 | #define DRIVER_LOADER_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | 10 | void load_drivers(); 11 | 12 | SYSCALL_HANDLER int load_driver(directory_stream* cwd, 13 | const file_handle* file); 14 | 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | #endif -------------------------------------------------------------------------------- /drivers/portio.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | global outb 3 | global inb 4 | 5 | section .text 6 | inb: ; uint8_t inb(uint16_t) 7 | push ebp 8 | mov ebp, esp 9 | mov edx, [ebp + 8] 10 | pop ebp 11 | in al, dx 12 | ret 13 | 14 | outb: ; void outb(uint16_t, uint8_t) 15 | push ebp 16 | mov ebp, esp 17 | mov eax, [ebp + 12] 18 | mov edx, [ebp + 8] 19 | out dx, al 20 | pop ebp 21 | ret 22 | -------------------------------------------------------------------------------- /configs/netboot/meson.build: -------------------------------------------------------------------------------- 1 | netrfs = custom_target( 2 | 'netboot_rfs', 3 | output : 'init.rfs', 4 | input : [ 5 | 'init.sys', 6 | driver_map.get('ps2mouse'), 7 | driver_map.get('i8042'), 8 | driver_map.get('at_kbrd'), 9 | driver_map.get('vesa'), 10 | listmode, 11 | shell, 12 | graphics, 13 | clib, 14 | terminal, 15 | init_loader, 16 | ], 17 | command : rdfs_command, 18 | build_by_default: true 19 | ) -------------------------------------------------------------------------------- /kernel/filesystem/drives.h: -------------------------------------------------------------------------------- 1 | #ifndef FS_DRIVES_H 2 | #define FS_DRIVES_H 3 | 4 | struct filesystem_virtual_drive; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #else 9 | typedef struct filesystem_virtual_drive filesystem_virtual_drive; 10 | #endif 11 | 12 | size_t filesystem_get_num_drives(); 13 | 14 | filesystem_virtual_drive* filesystem_get_drive(size_t index); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif -------------------------------------------------------------------------------- /clib/assert.cpp: -------------------------------------------------------------------------------- 1 | #ifndef NDEBUG 2 | 3 | #include 4 | #include 5 | 6 | extern "C" [[noreturn]] void __assert_fail(const char* expression, const char* file, int line) 7 | { 8 | printf("%s %s %d", expression, file, line); 9 | #ifdef __KERNEL 10 | __asm__ volatile ("cli;hlt"); 11 | #else 12 | while(true) 13 | { 14 | __asm__ volatile("nop"); 15 | } 16 | #endif 17 | __builtin_unreachable(); 18 | } 19 | 20 | #endif -------------------------------------------------------------------------------- /drivers/driver.ld: -------------------------------------------------------------------------------- 1 | PHDRS 2 | { 3 | headers PT_PHDR PHDRS ; 4 | interp PT_INTERP ; 5 | /* text PT_LOAD FILEHDR PHDRS ; */ 6 | data PT_LOAD FILEHDR PHDRS; 7 | dynamic PT_DYNAMIC ; 8 | } 9 | 10 | SECTIONS 11 | { 12 | . = SIZEOF_HEADERS; 13 | .interp : { *(.interp) } :data :interp 14 | .text : { *(.text) } :data 15 | .rodata : { *(.rodata) } 16 | .data : { *(.data) } :data 17 | .dynamic : { *(.dynamic) } :data :dynamic 18 | } -------------------------------------------------------------------------------- /CppProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "inheritEnvironments": [ 5 | "vsdev" 6 | ], 7 | "name": "clang", 8 | "includePath": [ 9 | "${workspaceRoot}\\**", 10 | "${workspaceRoot}\\cpplib\\include" 11 | ], 12 | "intelliSenseMode": "windows-clang-x86", 13 | "compilerSwitches": "-std=c++20 --target=i386-pc-freebsd-elf -nostdlib -nostdinc -Wconversion -Wall" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /kernel/rt_device.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "rt_device.h" 4 | 5 | static std::vector devices; 6 | 7 | rt_device* find_realtime_device(int class_ID) 8 | { 9 | for(auto* d : devices) 10 | { 11 | if(d->class_ID == class_ID) 12 | return d; 13 | } 14 | 15 | return nullptr; 16 | } 17 | 18 | void add_realtime_device(rt_device* d) 19 | { 20 | devices.push_back(d); 21 | } 22 | 23 | void remove_realtime_device(rt_device* d) 24 | { 25 | } 26 | -------------------------------------------------------------------------------- /kernel/input.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_H 2 | #define INPUT_H 3 | 4 | #define DISPLAY_H 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | void handle_input_event(input_event e); 14 | SYSCALL_HANDLER int get_input_event(input_event* e, bool wait); 15 | 16 | SYSCALL_HANDLER int get_keystate(key_type key); 17 | 18 | 19 | #ifdef __cplusplus 20 | } 21 | #endif 22 | 23 | #endif -------------------------------------------------------------------------------- /common/input_event.h: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_EVENT 2 | #define INPUT_EVENT 3 | 4 | #include 5 | 6 | enum event_type 7 | { 8 | BUTTON_DOWN = 0, 9 | BUTTON_UP, 10 | KEY_DOWN, 11 | KEY_UP, 12 | AXIS_MOTION 13 | }; 14 | 15 | typedef enum event_type event_type; 16 | 17 | struct input_event 18 | { 19 | size_t device_index; 20 | size_t control_index; 21 | int data; 22 | event_type type; 23 | clock_t time_stamp; 24 | }; 25 | 26 | typedef struct input_event input_event; 27 | 28 | #endif -------------------------------------------------------------------------------- /drivers/cmos.h: -------------------------------------------------------------------------------- 1 | #ifndef CMOS_H 2 | #define CMOS_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | inline int cmos_get_update_flag() 12 | { 13 | outb(0x70, 0x0A); 14 | return (inb(0x71) & 0x80); 15 | } 16 | 17 | inline uint8_t cmos_get_register(uint8_t reg) 18 | { 19 | outb(0x70, reg); 20 | return inb(0x71); 21 | } 22 | 23 | clock_t cmos_get_date_time(struct tm* result); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | #endif -------------------------------------------------------------------------------- /drivers/isa_dma.h: -------------------------------------------------------------------------------- 1 | #ifndef ISA_DMA_H 2 | #define ISA_DMA_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | enum dma_mode { 12 | ISA_DMA_READ = 0x44, 13 | ISA_DMA_WRITE = 0x48 14 | }; 15 | 16 | void isa_dma_begin_transfer(uint8_t channel, uint8_t mode, const uint8_t* buf, size_t length); 17 | uint8_t* isa_dma_allocate_buffer(size_t size); 18 | int isa_dma_free_buffer(uint8_t* buffer, size_t size); 19 | 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | 24 | #endif -------------------------------------------------------------------------------- /apps/fwrite.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char** argv) 7 | { 8 | auto root = open_dir_handle(get_root_directory(1), 0); 9 | 10 | std::string_view name = "time.txt"; 11 | 12 | auto file = open(root, name.data(), name.size(), FILE_WRITE | FILE_CREATE); 13 | 14 | auto tm = time(nullptr); 15 | 16 | auto dt = ctime(&tm); 17 | 18 | write(0, dt, strlen(dt), file); 19 | 20 | close(file); 21 | 22 | close_dir(root); 23 | 24 | return 0; 25 | } -------------------------------------------------------------------------------- /clib/include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef STDDEF_H 2 | #define STDDEF_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | 9 | #define offsetof(st, m) __builtin_offsetof(st, m) 10 | 11 | #ifndef NULL 12 | #define NULL (void*)0 13 | #endif 14 | 15 | #define _HAVE_SIZE_T 16 | typedef uint32_t size_t; 17 | 18 | typedef intptr_t ptrdiff_t; 19 | 20 | typedef long double max_align_t; 21 | 22 | #ifdef __cplusplus 23 | } 24 | 25 | namespace std 26 | { 27 | using nullptr_t = decltype(nullptr); 28 | } 29 | #endif 30 | #endif -------------------------------------------------------------------------------- /test.bat: -------------------------------------------------------------------------------- 1 | echo "this is a test" echo "this is a test" echo "this is a test" 2 | echo "this is a test" echo "this is a test" 3 | echo "this is a test" echo "this is a test" echo "this is a test" 4 | echo "this is a test" echo "this is a test" echo "this is a test" 5 | echo "this is a test" echo "this is a test" 6 | echo "this is a test" echo "this is a test" echo "this is a test" 7 | echo "this is a test" echo "this is a test" 8 | echo "this is a test" echo "this is a test" echo "this is a test" 9 | echo "this is a test" 10 | echo "this is a test"44 -------------------------------------------------------------------------------- /common/task_data.h: -------------------------------------------------------------------------------- 1 | #ifndef TASK_DATA_H 2 | #define TASK_DATA_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | typedef size_t task_id; 9 | 10 | typedef struct 11 | { 12 | void* pointer; 13 | size_t image_size; 14 | size_t total_size; 15 | size_t alignment; 16 | } tls_image_data; 17 | 18 | typedef struct 19 | { 20 | task_id pid; 21 | tls_image_data tls; 22 | } process_info; 23 | 24 | #define INVALID_TASK_ID (~(task_id)0x0) 25 | 26 | #define WAIT_FOR_PROCESS 0x01 27 | #ifdef __cplusplus 28 | } 29 | #endif 30 | 31 | #endif -------------------------------------------------------------------------------- /clib/include/stdint.h: -------------------------------------------------------------------------------- 1 | #ifndef STDINT_H 2 | #define STDINT_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | typedef char int8_t; 8 | typedef unsigned char uint8_t; 9 | typedef short int16_t; 10 | typedef unsigned short uint16_t; 11 | typedef int int32_t; 12 | typedef unsigned int uint32_t; 13 | typedef long long int64_t; 14 | typedef unsigned long long uint64_t; 15 | 16 | typedef int64_t intmax_t; 17 | typedef uint64_t uintmax_t; 18 | 19 | typedef int32_t intptr_t; 20 | typedef uint32_t uintptr_t; 21 | 22 | #ifdef __cplusplus 23 | } 24 | #endif 25 | #endif -------------------------------------------------------------------------------- /kernel/shared_mem.h: -------------------------------------------------------------------------------- 1 | #ifndef SHARED_MEM_H 2 | #define SHARED_MEM_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | SYSCALL_HANDLER uintptr_t create_shared_buffer(const char* name, size_t name_len, size_t size); 12 | SYSCALL_HANDLER uintptr_t open_shared_buffer(const char* name, size_t name_len); 13 | SYSCALL_HANDLER void close_shared_buffer(uintptr_t buf_handle); 14 | SYSCALL_HANDLER void* map_shared_buffer(uintptr_t buf_handle, size_t size, page_flags_t flags); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif -------------------------------------------------------------------------------- /clib/include/stdlib.h: -------------------------------------------------------------------------------- 1 | #ifndef STDLIB_H 2 | #define STDLIB_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | 9 | int atoi(const char* str); 10 | 11 | void* aligned_alloc(size_t alignment, size_t size); 12 | void* malloc(size_t size); 13 | void* realloc(void* ptr, size_t size); 14 | void* calloc(size_t, size_t); 15 | void free(void* ptr); 16 | 17 | #ifndef __KERNEL 18 | void exit(int status); 19 | 20 | int system(const char* command); 21 | #endif 22 | 23 | 24 | inline int abs(int n) 25 | { 26 | return n > 0 ? n : -n; 27 | } 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | #endif -------------------------------------------------------------------------------- /shell/shell.h: -------------------------------------------------------------------------------- 1 | #ifndef SHELL_H 2 | #define SHELL_H 3 | 4 | #include 5 | #include 6 | 7 | terminal& get_terminal(); 8 | const file_handle* get_current_dir(); 9 | void clear_console(); 10 | 11 | file_h find_file_in_dir(directory_stream* dir, file_info* f, 12 | const std::string_view name); 13 | file_h find_file_in_dir(file_info* f, const std::string_view name); 14 | 15 | template 16 | inline void print_strings(Args&&... args) 17 | { 18 | (get_terminal().print(std::forward(args)), ...); 19 | } 20 | 21 | inline void print_chars(char c, size_t num) 22 | { 23 | get_terminal().print(c, num); 24 | } 25 | 26 | #endif -------------------------------------------------------------------------------- /kernel/bootstrap/boot_info.h: -------------------------------------------------------------------------------- 1 | #ifndef BOOT_INFO_H 2 | #define BOOT_INFO_H 3 | 4 | #include 5 | #include 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | typedef struct 10 | { 11 | //all adresses are physical 12 | uintptr_t kernel_location; 13 | size_t kernel_size; 14 | 15 | uintptr_t ramdisk_location; 16 | size_t ramdisk_size; 17 | 18 | uintptr_t memmap_location; 19 | size_t memmap_size; 20 | 21 | size_t high_memory; 22 | size_t low_memory; 23 | } boot_info; 24 | 25 | void parse_boot_info(); 26 | 27 | void reserve_boot_mem(); 28 | 29 | extern boot_info boot_information; 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | #endif 35 | -------------------------------------------------------------------------------- /shell/util.h: -------------------------------------------------------------------------------- 1 | #ifndef SHELL_UTILS_H 2 | #define SHELL_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | struct dir_deleter { 8 | void operator()(directory_stream* b) { close_dir(b); } 9 | }; 10 | 11 | using directory_ptr = std::unique_ptr ; 12 | 13 | struct file_deleter { 14 | void operator()(file_stream* b) { close(b); } 15 | }; 16 | 17 | using file_ptr = std::unique_ptr ; 18 | 19 | struct file_handle_deleter { 20 | void operator()(const file_handle* f) { dispose_file_handle(f); } 21 | }; 22 | 23 | using file_h = std::unique_ptr ; 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /drivers/rs232.h: -------------------------------------------------------------------------------- 1 | #ifndef RS232_H 2 | #define RS232_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | 8 | #define COM1 0x3f8 //port arguments for rs232_init 9 | #define COM2 0x2F8 10 | #define COM3 0x3E8 11 | #define COM4 0x2E8 12 | 13 | char rs232_read_byte(unsigned int port); 14 | void rs232_init(unsigned int port, unsigned int rate); 15 | int rs232_isclear(unsigned int port); 16 | int rs232_data_available(unsigned int port); 17 | void rs232_send_byte(unsigned int port, char b); 18 | void rs232_send_string(unsigned int port, const char* c); 19 | void rs232_send_string_len(unsigned int port, const char* b, size_t len); 20 | #ifdef __cplusplus 21 | } 22 | #endif 23 | #endif -------------------------------------------------------------------------------- /apps/bkgrnd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | terminal s_term{"terminal_1"}; 8 | 9 | int main(int argc, char** argv) 10 | { 11 | set_stdout( 12 | [](const char* buf, size_t size, void* impl) 13 | { 14 | s_term.print(buf, size); 15 | return size; 16 | }); 17 | 18 | auto end = clock() + (60 * CLOCKS_PER_SEC); 19 | while(clock() < end) 20 | { 21 | for(size_t i = 0; i < 10; i++) 22 | { 23 | printf("%d", i); 24 | auto next = clock() + (CLOCKS_PER_SEC); 25 | while(clock() < next); 26 | } 27 | printf("\n"); 28 | } 29 | 30 | printf("BANG!\n"); 31 | 32 | return 0; 33 | } -------------------------------------------------------------------------------- /cpplib/include/new: -------------------------------------------------------------------------------- 1 | #ifndef STD_NEW_H 2 | #define STD_NEW_H 3 | 4 | namespace std 5 | { 6 | enum class align_val_t : size_t 7 | { 8 | }; 9 | } 10 | 11 | [[nodiscard]] void* operator new(size_t count); 12 | [[nodiscard]] void* operator new[](size_t count); 13 | [[nodiscard]] void* operator new(size_t count, std::align_val_t align); 14 | [[nodiscard]] void* operator new[](size_t count, std::align_val_t align); 15 | 16 | [[nodiscard]] inline void* operator new(size_t, void* p) throw() { return p; } 17 | [[nodiscard]] inline void* operator new[](size_t, void* p) throw() { return p; } 18 | inline void operator delete (void*, void*) throw() {}; 19 | inline void operator delete[](void*, void*) throw() {}; 20 | 21 | #endif -------------------------------------------------------------------------------- /apps/primes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | bool is_prime(size_t number) 5 | { 6 | for(size_t i = 2; i < number; i++) 7 | { 8 | if(number % i == 0) 9 | { 10 | return false; 11 | } 12 | } 13 | return true; 14 | } 15 | 16 | terminal s_term{"terminal_1"}; 17 | 18 | int main(int argc, char** argv) 19 | { 20 | set_stdout( 21 | [](const char* buf, size_t size, void* impl) 22 | { 23 | s_term.print(buf, size); 24 | return size; 25 | }); 26 | 27 | size_t number = 2; 28 | while(true) 29 | { 30 | if(is_prime(number)) 31 | { 32 | printf("%d\n", number); 33 | } 34 | number++; 35 | } 36 | 37 | return 0; 38 | } -------------------------------------------------------------------------------- /apps/listmode.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | terminal s_term{"terminal_1"}; 7 | 8 | int main(int argc, char** argv) 9 | { 10 | set_stdout( 11 | [](const char* buf, size_t size, void* impl) 12 | { 13 | s_term.print(buf, size); 14 | return size; 15 | }); 16 | 17 | display_mode mode; 18 | int i = 0; 19 | while(get_display_mode(i, &mode) == 0) 20 | { 21 | if(mode.flags & DISPLAY_TEXT_MODE) 22 | printf("text "); 23 | else 24 | printf("graphics "); 25 | 26 | printf("%-4d x %-4d @ %-2d", mode.width, mode.height, mode.bpp); 27 | 28 | if(i & 1) 29 | putchar('\n'); 30 | else 31 | putchar('\t'); 32 | 33 | i++; 34 | } 35 | return 42; 36 | } -------------------------------------------------------------------------------- /kernel/physical_manager.h: -------------------------------------------------------------------------------- 1 | #ifndef _PHYSICAL_MANAGER_H 2 | #define _PHYSICAL_MANAGER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | void physical_memory_init(void); 14 | 15 | SYSCALL_HANDLER size_t physical_num_bytes_free(void); 16 | size_t physical_mem_size(void); 17 | 18 | uintptr_t physical_memory_allocate_in_range(uintptr_t start, uintptr_t end, size_t size, size_t align); 19 | uintptr_t physical_memory_allocate(size_t size, size_t align); 20 | 21 | void physical_memory_free(uintptr_t physical_address, size_t size); 22 | 23 | void physical_memory_reserve(uintptr_t address, size_t size); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | #endif -------------------------------------------------------------------------------- /clib/include/limits.h: -------------------------------------------------------------------------------- 1 | #ifndef LIMITS_H 2 | #define LIMITS_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #define CHAR_BIT 8 9 | #define SCHAR_MIN -127 10 | #define SCHAR_MAX 127 11 | #define UCHAR_MAX 255 12 | #define CHAR_MIN SCHAR_MIN 13 | #define CHAR_MAX SCHAR_MAX 14 | #define MB_LEN_MAX 1 15 | #define SHRT_MIN -32767 16 | #define SHRT_MAX 32767 17 | #define USHRT_MAX 65535 18 | #define INT_MIN -2147483647 19 | #define INT_MAX 2147483647 20 | #define UINT_MAX 4294967295 21 | #define LONG_MIN -2147483647 22 | #define LONG_MAX 2147483647 23 | #define ULONG_MAX 4294967295 24 | #define LLONG_MIN -9223372036854775807 25 | #define LLONG_MAX 9223372036854775807 26 | #define ULLONG_MAX 18446744073709551615 27 | 28 | #ifdef __cplusplus 29 | } 30 | #endif 31 | 32 | #endif -------------------------------------------------------------------------------- /clib/ctype.c: -------------------------------------------------------------------------------- 1 | const char __ctype[] = 2 | { 3 | 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x28, 0x28, 0x28, 0x8, 4 | 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 5 | 0x8, 0x20, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 6 | 0x10, 0x10, 0x10, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44, 7 | 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x1, 8 | 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 9 | 0x1, 0x1, 0x1, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x42, 0x42, 0x42, 0x42, 10 | 0x42, 0x42, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 11 | 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x10, 0x10, 0x10, 0x10, 0x8, 12 | }; 13 | 14 | const char *_ctype = __ctype; -------------------------------------------------------------------------------- /kernel/rt_device.h: -------------------------------------------------------------------------------- 1 | #ifndef REALTIME_DEVICE 2 | #define REALTIME_DEVICE 3 | #include 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | struct rt_device; 11 | 12 | typedef void (data_handler)(rt_device* device, const uint8_t* data, size_t length); 13 | typedef void (read_handler)(rt_device* device, uint8_t* data, size_t length); 14 | 15 | struct rt_device 16 | { 17 | int class_ID; 18 | 19 | read_handler* read_bytes; 20 | data_handler* send_bytes; 21 | data_handler* on_new_data; 22 | void (*on_removed)(rt_device* device); 23 | 24 | void* impl_data; 25 | }; 26 | 27 | rt_device* find_realtime_device(int class_ID); 28 | 29 | void add_realtime_device(rt_device* d); 30 | void remove_realtime_device(rt_device* d); 31 | 32 | 33 | #ifdef __cplusplus 34 | } 35 | #endif 36 | 37 | #endif -------------------------------------------------------------------------------- /cpplib/include/atomic: -------------------------------------------------------------------------------- 1 | #ifndef STD_ATOMIC_H 2 | #define STD_ATOMIC_H 3 | namespace std 4 | { 5 | typedef enum memory_order 6 | { 7 | relaxed = __ATOMIC_RELAXED, 8 | consume = __ATOMIC_CONSUME, 9 | acquire = __ATOMIC_ACQUIRE, 10 | release = __ATOMIC_RELEASE, 11 | acq_rel = __ATOMIC_ACQ_REL, 12 | seq_cst = __ATOMIC_SEQ_CST 13 | } memory_order; 14 | 15 | inline constexpr memory_order memory_order_relaxed = memory_order::relaxed; 16 | inline constexpr memory_order memory_order_consume = memory_order::consume; 17 | inline constexpr memory_order memory_order_acquire = memory_order::acquire; 18 | inline constexpr memory_order memory_order_release = memory_order::release; 19 | inline constexpr memory_order memory_order_acq_rel = memory_order::acq_rel; 20 | inline constexpr memory_order memory_order_seq_cst = memory_order::seq_cst; 21 | 22 | } 23 | #endif -------------------------------------------------------------------------------- /kernel/sys/syscalls.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSCALLS_H 2 | #define SYSCALLS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define open filesystem_open_file 17 | #define close filesystem_close_file 18 | #define read filesystem_read_file 19 | #define exit syscall_exit 20 | #define master_time sysclock_get_master_time 21 | #define clock_ticks sysclock_get_ticks 22 | #define get_utc_offset sysclock_get_utc_offset 23 | #define alloc_pages memmanager_virtual_alloc 24 | #define free_pages memmanager_free_pages 25 | #define getkey get_keypress 26 | #define wait_and_getkey wait_and_get_keypress 27 | #endif -------------------------------------------------------------------------------- /cpplib/include/charconv: -------------------------------------------------------------------------------- 1 | #ifndef STD_FROM_CHARS_H 2 | #define STD_FROM_CHARS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace std 9 | { 10 | enum class errc { 11 | invalid_argument = 1 12 | }; 13 | 14 | struct from_chars_result { 15 | const char* ptr; 16 | errc ec; 17 | }; 18 | 19 | inline from_chars_result from_chars(const char* first, const char* last, unsigned int& value) 20 | { 21 | const char* str = first; 22 | while(isspace(*str)) 23 | { 24 | str++; 25 | if(str >= last) 26 | return {first, errc::invalid_argument}; 27 | 28 | } 29 | 30 | unsigned int n = 0; 31 | while(str < last && isdigit(*str)) 32 | { 33 | n = (n * 10) + static_cast(*str - '0'); 34 | str++; 35 | } 36 | 37 | value = n; 38 | 39 | return {str, {}}; 40 | } 41 | }; 42 | 43 | #endif -------------------------------------------------------------------------------- /kernel/sysclock.h: -------------------------------------------------------------------------------- 1 | #ifndef SYSCLOCK_H 2 | #define SYSCLOCK_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | #include 7 | 8 | #include 9 | 10 | void sysclock_set_utc_offset(int offset); 11 | void sysclock_init(); 12 | 13 | typedef enum { 14 | SECONDS = 1, 15 | MILLISECONDS = SECONDS * 1000, 16 | MICROSECONDS = MILLISECONDS * 1000 17 | } clock_unit; 18 | 19 | typedef uint64_t tick_t; 20 | 21 | void sysclock_sleep(size_t time, clock_unit unit); 22 | 23 | clock_t sysclock_get_ticks(); 24 | size_t sysclock_get_rate(); 25 | SYSCALL_HANDLER time_t sysclock_get_master_time(void); 26 | 27 | SYSCALL_HANDLER clock_t syscall_get_ticks(size_t* rate); //return the ticks since the system booted 28 | SYSCALL_HANDLER int sysclock_get_utc_offset(void); //returns the UTC offset in seconds 29 | 30 | #ifdef __cplusplus 31 | } 32 | #endif 33 | #endif -------------------------------------------------------------------------------- /kernel/syscall.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | [extern num_syscalls] 3 | [extern syscall_table] 4 | global handle_syscall 5 | 6 | handle_syscall: 7 | sti 8 | cmp ebx, num_syscalls 9 | ja .invalid_call 10 | push ds 11 | push es 12 | push fs 13 | push gs 14 | 15 | push 0x30 16 | pop fs 17 | 18 | call [syscall_table+4*ebx] 19 | pop gs 20 | pop fs 21 | pop es 22 | pop ds 23 | iret 24 | .invalid_call: 25 | mov eax, 0xFFFFFFFF 26 | o32 iret 27 | 28 | struc FRAME 29 | .eip0: resd 1 30 | .gs: resd 1 31 | .fs: resd 1 32 | .es: resd 1 33 | .ds: resd 1 34 | .eip: resd 1 35 | .cs: resd 1 36 | .eflags:resd 1 37 | .esp: resd 1 38 | .ss: resd 1 39 | endstruc 40 | 41 | global __regcall3__iopl 42 | 43 | __regcall3__iopl: 44 | mov ecx, [esp + FRAME.eflags] 45 | and ecx, 0xFFFFCFFF 46 | shl eax, 12 47 | and eax, 0x00003000 48 | or ecx, eax 49 | mov [esp + FRAME.eflags], ecx 50 | xor eax, eax 51 | ret 52 | -------------------------------------------------------------------------------- /apps/threads.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | terminal s_term{"terminal_1"}; 7 | 8 | thread_local int tls_test = 55; 9 | 10 | int main(int argc, char** argv) 11 | { 12 | set_stdout( 13 | [](const char* buf, size_t size, void* impl) 14 | { 15 | s_term.print(buf, size); 16 | return size; 17 | }); 18 | 19 | init_first_thread(); 20 | 21 | printf("TLS data = %d, main thread\n", tls_test); 22 | 23 | auto tid = spawn_thread( 24 | []() 25 | { 26 | tls_test = 1; 27 | for(size_t i = 0; i < 10; i++) 28 | { 29 | printf("TLS data = %d, this is a test from another thread!\n", 30 | tls_test); 31 | 32 | yield_to(INVALID_TASK_ID); 33 | } 34 | }); 35 | 36 | printf("Spawned new thread tid = %d\n", tid); 37 | 38 | for(size_t i = 0; i < 10; i++) 39 | { 40 | printf("TLS data = %d, main thread\n", tls_test); 41 | yield_to(tid); 42 | } 43 | 44 | return 0; 45 | } -------------------------------------------------------------------------------- /clib/include/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef ASSERT_H 2 | #define ASSERT_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" 6 | { 7 | #endif 8 | 9 | #ifndef NDEBUG 10 | 11 | # ifdef __cplusplus 12 | [[noreturn]] 13 | # endif 14 | __attribute__((noinline)) void 15 | __assert_fail(const char* expression, const char* file, int line); 16 | 17 | # ifdef __cplusplus 18 | # define assert(expression) \ 19 | if(!(expression)) [[unlikely]] \ 20 | { \ 21 | __assert_fail(#expression, __FILE__, __LINE__); \ 22 | } 23 | # else 24 | # define assert(expression) \ 25 | if(!(expression)) \ 26 | { \ 27 | __assert_fail(#expression, __FILE__, __LINE__); \ 28 | } 29 | # endif 30 | 31 | #else 32 | 33 | # define assert(expression) 34 | 35 | #endif 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif -------------------------------------------------------------------------------- /kernel/dynamic_object.h: -------------------------------------------------------------------------------- 1 | #ifndef DYNAMIC_OBJECT_H 2 | #define DYNAMIC_OBJECT_H 3 | #ifdef __cplusplus 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | struct segment 12 | { 13 | void* pointer; 14 | size_t num_pages; 15 | }; 16 | 17 | struct dynamic_object 18 | { 19 | using sym_map = hash_map; 20 | 21 | void* entry_point = nullptr; 22 | std::vector segments; 23 | 24 | tls_image_data tls_image = { 25 | .pointer = nullptr, 26 | .image_size = 0, 27 | .total_size = 0, 28 | .alignment = 1, 29 | }; 30 | 31 | void* linker_data = nullptr; 32 | 33 | sym_map* lib_set = nullptr; 34 | sym_map* symbol_map = nullptr; 35 | sym_map* glob_data_symbol_map = nullptr; 36 | 37 | constexpr dynamic_object(sym_map* libs, sym_map* symbols, sym_map* glob_data) 38 | : lib_set(libs) 39 | , symbol_map(symbols) 40 | , glob_data_symbol_map(glob_data) {} 41 | }; 42 | 43 | #endif 44 | #endif -------------------------------------------------------------------------------- /cpplib/include/bit: -------------------------------------------------------------------------------- 1 | #ifndef STD_BIT_H 2 | #define STD_BIT_H 3 | 4 | #include 5 | 6 | namespace std { 7 | 8 | template 9 | constexpr ToType bit_cast(FromType const& from) noexcept 10 | requires(sizeof(ToType) == sizeof(FromType) && 11 | is_trivially_copyable_v && 12 | is_trivially_copyable_v) 13 | { 14 | return __builtin_bit_cast(ToType, from); 15 | } 16 | 17 | template 18 | constexpr int countl_zero(T x) noexcept 19 | { 20 | return __builtin_clz(static_cast(x)); 21 | } 22 | 23 | template 24 | constexpr int countl_one(T x) noexcept 25 | { 26 | return countl_zero(~x); 27 | } 28 | 29 | template 30 | constexpr int countr_zero(T x) noexcept 31 | { 32 | return __builtin_ctz(static_cast(x)); 33 | } 34 | 35 | template 36 | constexpr bool has_single_bit(T x) noexcept 37 | { 38 | return x != 0 && (x & (x - 1)) == 0; 39 | } 40 | } 41 | 42 | #endif -------------------------------------------------------------------------------- /drivers/cpu/ap_bootstrap.asm: -------------------------------------------------------------------------------- 1 | [bits 16] 2 | [org 0x7000] 3 | 4 | ap_bootstrap_begin: 5 | cli 6 | cld 7 | 8 | xor ax, ax 9 | mov ds, ax 10 | 11 | lgdt [ds:flat_gdt_descriptor] 12 | mov eax, cr0 13 | or eax, 0x01 14 | mov cr0, eax 15 | 16 | jmp 0x08 : pmode 17 | 18 | [bits 32] 19 | pmode: 20 | mov ax, 0x10 21 | mov ss, ax 22 | mov ds, ax 23 | mov es, ax 24 | mov ebp, stack.top 25 | mov esp, ebp 26 | 27 | mov eax, dword [page_dir] 28 | mov cr3, eax 29 | 30 | mov eax, cr0 31 | or eax, 0x80000001 32 | mov cr0, eax 33 | 34 | mov eax, dword [processor_id] 35 | mov [esp + 4], eax 36 | jmp [entry_point] 37 | 38 | stack: 39 | align 4 40 | times 1024 db 0 41 | .top: 42 | 43 | flat_gdt: 44 | dq 0 45 | dd 0x0000FFFF 46 | dd 0x00CF9A00 47 | dd 0x0000FFFF 48 | dd 0x00CF9200 49 | ;dd 0x00000068 50 | ;dd 0x00CF8900 51 | flat_gdt_end: 52 | 53 | flat_gdt_descriptor : 54 | dw flat_gdt_end - flat_gdt - 1 55 | dd flat_gdt 56 | 57 | ap_bootstrap_params: 58 | page_dir: dd 0 59 | entry_point: dd 0 60 | processor_id: dd 0 -------------------------------------------------------------------------------- /mesoncross.ini: -------------------------------------------------------------------------------- 1 | [constants] 2 | arch = 'i386-pc-freebsd-elf' 3 | common_flags = [ 4 | '--target=' + arch, 5 | '-Wuninitialized', 6 | '-Wall', 7 | '-fno-unwind-tables', 8 | '-fno-asynchronous-unwind-tables', 9 | '-march=i386', 10 | '-mno-sse', 11 | '-mno-mmx', 12 | '-I ./', 13 | '-D__I386_ONLY', 14 | '-nostdlib', 15 | '-nostdinc' 16 | ] 17 | [binaries] 18 | c = 'clang' 19 | c_ld = 'lld' 20 | cpp_ld = 'lld' 21 | cpp = 'clang++' 22 | 23 | [properties] 24 | needs_exe_wrapper = true 25 | 26 | [built-in options] 27 | c_args = common_flags + [ 28 | '-std=c99', 29 | '-Wc++-compat', 30 | ] 31 | cpp_args = common_flags + [ 32 | '-std=c++20', 33 | '-fno-rtti', 34 | '-fno-exceptions', 35 | ] 36 | c_link_args = [ 37 | '--target=' + arch, 38 | '-L./', 39 | '-l:libclang_rt.builtins-i386.a', 40 | '-Wl,-nostdlib', 41 | '-nostdlib', 42 | '-Wl,--dynamic-linker=lnk' 43 | ] 44 | cpp_link_args = c_link_args 45 | 46 | [host_machine] 47 | system = 'none' 48 | cpu_family = 'x86' 49 | cpu = 'i386' 50 | endian = 'little' 51 | strip = true 52 | -------------------------------------------------------------------------------- /clib/internal_file.h: -------------------------------------------------------------------------------- 1 | #ifndef CLIB_INTERNAL_FILE 2 | #define CLIB_INTERNAL_FILE 3 | 4 | #include 5 | #include 6 | 7 | struct FILE 8 | { 9 | inline size_t write(const char* buf, size_t size) 10 | { 11 | return m_write(buf, size, this); 12 | } 13 | inline size_t read(char* buf, size_t size) 14 | { 15 | return m_read(buf, size, this); 16 | } 17 | inline file_size_t get_pos() 18 | { 19 | return m_get_pos(this); 20 | } 21 | inline int set_pos(file_size_t pos) 22 | { 23 | return m_set_pos(pos, this); 24 | } 25 | inline file_size_t end() 26 | { 27 | return m_end(this); 28 | } 29 | inline int close() 30 | { 31 | return m_close(this); 32 | } 33 | 34 | size_t (*m_write)(const char* buf, size_t size, FILE* impl) = nullptr; 35 | size_t (*m_read)(char* buf, size_t size, FILE* impl) = nullptr; 36 | file_size_t (*m_get_pos)(FILE* impl) = nullptr; 37 | int (*m_set_pos)(file_size_t pos, FILE* impl) = nullptr; 38 | file_size_t (*m_end)(FILE* impl) = nullptr; 39 | int (*m_close)(FILE* impl) = nullptr; 40 | }; 41 | 42 | #endif -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build-iso: 7 | name: Build ISO 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | with: 12 | submodules: recursive 13 | - uses: actions/setup-python@v1 14 | - uses: egor-tensin/setup-clang@v1 15 | with: 16 | version: latest 17 | platform: x64 18 | 19 | - uses: shogo82148/actions-setup-perl@v1 20 | with: 21 | perl-version: '5.34' 22 | 23 | - uses: ConorMacBride/install-package@v1 24 | with: 25 | apt: xorriso 26 | 27 | - uses: ilammy/setup-nasm@v1 28 | 29 | - uses: BSFishy/meson-build@v1.0.3 30 | with: 31 | action: build 32 | directory: build 33 | setup-options: --cross-file mesoncross.ini 34 | meson-version: 0.56.2 35 | 36 | - uses: actions/upload-artifact@v3 37 | with: 38 | name: os-image 39 | path: build/jsd-os+limine.iso 40 | -------------------------------------------------------------------------------- /clib/include/string.h: -------------------------------------------------------------------------------- 1 | #ifndef STRING_H 2 | #define STRING_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | //extern void* memcpy(void* dest, const void* src, size_t num); 11 | //extern void* memset(void* ptr, int value, size_t num); 12 | extern void* memmove(void* dest, const void* src, size_t num); 13 | void* memchr(const void* str, int c, size_t n); 14 | int memcmp(const void* ptr1, const void* ptr2, size_t num); 15 | 16 | size_t strlen(const char* str); 17 | int strncmp(const char* lhs, const char* rhs, size_t count); 18 | int strcmp(const char* str1, const char* str2); 19 | char* strtok(char* str, const char* delimiters); 20 | char* strchr(const char* str, int character); 21 | 22 | char* strcat(char* destination, const char* source); 23 | char* strcpy(char* destination, const char* source); 24 | 25 | char* strncpy(char* dst, const char* src, size_t count); 26 | 27 | char* strstr(const char* str, const char* substr); 28 | 29 | char* strrchr(const char*, int); 30 | 31 | #ifdef __cplusplus 32 | } 33 | #endif 34 | 35 | #include 36 | 37 | #endif -------------------------------------------------------------------------------- /kernel/multiboot.h: -------------------------------------------------------------------------------- 1 | #ifndef MULTIBOOT_H 2 | #define MULTIBOOT_H 3 | 4 | #include 5 | 6 | typedef struct 7 | { 8 | uint32_t begin; 9 | uint32_t end; 10 | } __attribute__((packed)) multiboot_modules; 11 | 12 | typedef struct 13 | { 14 | uint32_t m_flags; 15 | uint32_t m_memoryLo; 16 | uint32_t m_memoryHi; 17 | uint32_t m_bootDevice; 18 | uint32_t m_cmdLine; 19 | uint32_t m_modsCount; 20 | uint32_t m_modsAddr; 21 | uint32_t m_syms0; 22 | uint32_t m_syms1; 23 | uint32_t m_syms2; 24 | uint32_t m_syms3; 25 | uint32_t m_mmap_length; 26 | uint32_t m_mmap_addr; 27 | uint32_t m_drives_length; 28 | uint32_t m_drives_addr; 29 | uint32_t m_config_table; 30 | uint32_t m_bootloader_name; 31 | uint32_t m_apm_table; 32 | uint32_t m_vbe_control_info; 33 | uint16_t m_vbe_mode_info; 34 | uint16_t m_vbe_mode; 35 | uint16_t m_vbe_interface_off; 36 | uint16_t m_vbe_interface_len; 37 | } __attribute__((packed)) multiboot_info; 38 | 39 | typedef struct 40 | { 41 | uint32_t m_size; 42 | uint64_t m_addr; 43 | uint64_t m_length; 44 | uint32_t m_type; 45 | } __attribute__((packed)) multiboot_mmap_entry; 46 | 47 | #endif -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to JSD/OS 2 | 3 | Contributions are welcome and encouraged! If you would like to add something to JSD/OS please feel free to submit a PR. 4 | 5 | ### Contributions that would be especially appreciated: 6 | - New hardware drivers (Display & Storage particularily, no hardware is too old) 7 | - New filesystem drivers (ext2, ext3, etc.) 8 | - Porting user mode libraries 9 | - New user mode programs & utilities 10 | 11 | ### Some guidelines: 12 | - All contributions should conform to the license of the main JSD/OS project unless otherwise specified 13 | - New code is preferably written in C++, as of right now JSD/OS conforms to the C++17 standard 14 | - Plain C is used and permitted but the kernel API is geared towards C++ 15 | - Please try to implement any hardware specific functionality as a module in the /drivers directory 16 | - Please avoid Racist/Homophobic/offensive language in comments (general swearing and FBombs are permitted) 17 | - Please use English language names and comments and avoid non-ASCII characters 18 | - Please use tabs not spaces and try to use Allman formatting if possible 19 | 20 | -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(start) 2 | phys = 0xFF800000; 3 | SECTIONS 4 | { 5 | . = 0xFF800000; 6 | .boot_entry_code phys : AT(phys) { 7 | _RECLAIMABLE_CODE_BEGIN_ = .; 8 | boot_entry_code = .; 9 | KEEP(*(.boot_entry_code*)) 10 | } 11 | .reclaimable_text : { 12 | reclaimable_text = .; 13 | KEEP(*(.reclaimable_text*)) 14 | _RECLAIMABLE_CODE_END_ = .; 15 | } 16 | .reclaimable_data : { 17 | _RECLAIMABLE_DATA_BEGIN_ = .; 18 | reclaimable_data = .; 19 | *(.reclaimable_data*) 20 | _RECLAIMABLE_DATA_END_ = .; 21 | } 22 | .text : { 23 | code = .; 24 | *(.text*) 25 | _TEXT_END_ = .; 26 | } 27 | .rodata : { 28 | rodata = .; 29 | *(.rodata*) 30 | _RODATA_END_ = .; 31 | } 32 | .data : { 33 | data = .; 34 | *(.data*) 35 | } 36 | .reclaimable_bss (NOLOAD) : { 37 | _DATA_END_ = .; 38 | _RECLAIMABLE_BSS_BEGIN_ = .; 39 | reclaimable_bss = .; 40 | KEEP(*(.reclaimable_bss*)) 41 | } 42 | _RECLAIMABLE_BSS_END_ = .; 43 | .bss : { 44 | bss = .; 45 | *(COMMON) 46 | KEEP(*(.bss*)) 47 | } 48 | _BSS_END_ = .; 49 | end = .; 50 | _IMAGE_END_ = .; 51 | /DISCARD/ : { 52 | *(.note*) 53 | *(.interp) 54 | } 55 | } -------------------------------------------------------------------------------- /cpplib/include/utility: -------------------------------------------------------------------------------- 1 | #ifndef STD_UTILITY_H 2 | #define STD_UTILITY_H 3 | 4 | #include 5 | 6 | namespace std 7 | { 8 | template< class T > 9 | constexpr remove_reference_t&& move(T&& t) noexcept { 10 | return static_cast::type&&>(t); 11 | } 12 | 13 | template 14 | inline constexpr enable_if_t && is_move_assignable_v> 15 | swap(T& t1, T& t2) noexcept(is_nothrow_move_constructible_v&& 16 | is_nothrow_move_assignable_v) 17 | { 18 | T temp = std::move(t1); 19 | t1 = std::move(t2); 20 | t2 = std::move(temp); 21 | } 22 | 23 | template 24 | inline constexpr T&& forward(typename remove_reference::type& t) noexcept 25 | { 26 | return static_cast(t); 27 | } 28 | 29 | template 30 | inline constexpr T&& forward(typename remove_reference::type&& t) noexcept 31 | { 32 | static_assert(!is_lvalue_reference::value, "cannot forward an rvalue as an lvalue"); 33 | return static_cast(t); 34 | } 35 | 36 | struct in_place_t 37 | { 38 | explicit in_place_t() = default; 39 | }; 40 | 41 | inline constexpr in_place_t in_place{}; 42 | } 43 | #endif -------------------------------------------------------------------------------- /boot/multiboot.asm: -------------------------------------------------------------------------------- 1 | struc multiboot_info 2 | .flags resd 1 ; required 3 | .memoryLo resd 1 ; memory size. Present if flags[0] is set 4 | .memoryHi resd 1 5 | .bootDevice resd 1 ; boot device. Present if flags[1] is set 6 | .cmdLine resd 1 ; kernel command line. Present if flags[2] is set 7 | .mods_count resd 1 ; number of modules loaded along with kernel. present if flags[3] is set 8 | .mods_addr resd 1 9 | ;.syms0 resd 1 ; symbol table info. present if flags[4] or flags[5] is set 10 | ;.syms1 resd 1 11 | ;.syms2 resd 1 12 | ;.mmap_length resd 1 ; memory map. Present if flags[6] is set 13 | ;.mmap_addr resd 1 14 | ;.drives_length resd 1 ; phys address of first drive structure. present if flags[7] is set 15 | ;.drives_addr resd 1 16 | ;.config_table resd 1 ; ROM configuation table. present if flags[8] is set 17 | ;.bootloader_name resd 1 ; Bootloader name. present if flags[9] is set 18 | ;.apm_table resd 1 ; advanced power management (apm) table. present if flags[10] is set 19 | ;.vbe_control_info resd 1 ; video bios extension (vbe). present if flags[11] is set 20 | ;.vbe_mode_info resd 1 21 | ;.vbe_mode resw 1 22 | ;.vbe_interface_seg resw 1 23 | ;.vbe_interface_off resw 1 24 | ;.vbe_interface_len resw 1 25 | endstruc 26 | 27 | struc multiboot_module 28 | .begin resd 1 29 | .end resd 1 30 | endstruc 31 | -------------------------------------------------------------------------------- /kernel/task.h: -------------------------------------------------------------------------------- 1 | #ifndef TASK_H 2 | #define TASK_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | 14 | typedef struct process process; 15 | 16 | struct dynamic_object; 17 | typedef struct dynamic_object dynamic_object; 18 | 19 | 20 | SYSCALL_HANDLER task_id spawn_process(const file_handle* file, 21 | const void* arg_ptr, size_t args_size, 22 | int flags); 23 | SYSCALL_HANDLER void exit_process(int val); 24 | 25 | SYSCALL_HANDLER task_id spawn_thread(void* function_ptr, void* tls_ptr); 26 | SYSCALL_HANDLER void exit_thread(int val); 27 | SYSCALL_HANDLER void yield_to(task_id task); 28 | 29 | SYSCALL_HANDLER void get_process_info(process_info* data); 30 | SYSCALL_HANDLER void set_tls_addr(void* tls_ptr); 31 | 32 | void run_next_task(); 33 | void run_background_tasks(); 34 | void setup_first_task(); 35 | void setup_boot_cpu(); 36 | task_id this_task_is_active(); 37 | void switch_to_task(task_id pid); 38 | void switch_to_active_task(); 39 | task_id get_active_process(); 40 | task_id get_running_task_id(); 41 | 42 | //should be called by a new cpu after boostrap 43 | void add_cpu(size_t id); 44 | void cpu_entry_point(size_t id, uint8_t* spinlock); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | #endif -------------------------------------------------------------------------------- /drivers/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef PCI_H 2 | #define PCI_H 3 | 4 | #define PCI_NONE 0xFFFF 5 | 6 | 7 | #define PCI_VENDOR_ID 0x00 // 2 8 | #define PCI_DEVICE_ID 0x02 // 2 9 | #define PCI_COMMAND 0x04 // 2 10 | #define PCI_STATUS 0x06 // 2 11 | #define PCI_REVISION_ID 0x08 // 1 12 | 13 | #define PCI_PROG_IF 0x09 // 1 14 | 15 | #define PCI_BAR0 0x10 // 4 16 | #define PCI_BAR1 0x14 // 4 17 | #define PCI_BAR2 0x18 // 4 18 | #define PCI_BAR3 0x1C // 4 19 | #define PCI_BAR4 0x20 // 4 20 | #define PCI_BAR5 0x24 // 4 21 | 22 | #define PCI_SUBCLASS 0x0a // 1 23 | #define PCI_CLASS 0x0b // 1 24 | 25 | #define PCI_INTERRUPT_LINE 0x3C // 1 26 | #define PCI_INTERRUPT_PIN 0x3D 27 | 28 | struct pci_device 29 | { 30 | uint8_t bus; 31 | uint8_t slot; 32 | uint8_t func; 33 | uint8_t padding; 34 | }; 35 | 36 | typedef void (*pci_func)(pci_device device, uint16_t vendor_id, uint16_t device_id, 37 | void* udata); 38 | 39 | void pci_device_by_class(pci_func f, 40 | size_t device_class, 41 | size_t device_subclass, 42 | void* extra); 43 | 44 | template T pci_read(pci_device device, size_t field); 45 | 46 | template void pci_write(pci_device device, size_t field, T value); 47 | 48 | #endif -------------------------------------------------------------------------------- /drivers/rs232.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "portio.h" 3 | #include "rs232.h" 4 | 5 | void rs232_init(unsigned int port, unsigned int rate) 6 | { 7 | uint32_t divisor = (uint32_t)(115200 / rate); 8 | 9 | outb(port + 1, 0x00); // Disable all interrupts 10 | outb(port + 3, 0x80); // Enable DLAB (set baud rate divisor) 11 | 12 | outb(port + 0, divisor & 0xFF); // Set divisor to 3 (lo byte) 38400 baud 13 | outb(port + 1, divisor >> 8); // (hi byte) 14 | 15 | outb(port + 3, 0x03); // 8 bits, no parity, one stop bit 16 | 17 | outb(port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold 18 | outb(port + 4, 0x0B); // IRQs enabled, RTS/DSR set 19 | } 20 | 21 | int rs232_data_available(unsigned int port) 22 | { 23 | return inb(port + 5) & 1; 24 | } 25 | 26 | char rs232_read_byte(unsigned int port) 27 | { 28 | while(rs232_data_available(port) == 0); 29 | return inb(port); 30 | } 31 | 32 | int rs232_isclear(unsigned int port) 33 | { 34 | return inb(port + 5) & 0x20; 35 | } 36 | 37 | void rs232_send_byte(unsigned int port, char b) 38 | { 39 | while(rs232_isclear(port) == 0); //wait until line is clear 40 | outb(port, b); 41 | } 42 | 43 | void rs232_send_string(unsigned int port, const char* c) 44 | { 45 | while(c++ != 0) { rs232_send_byte(port, *c); } 46 | } 47 | 48 | void rs232_send_string_len(unsigned int port, const char* b, size_t len) 49 | { 50 | size_t i; 51 | for(i = 0; i < len; i++) 52 | { 53 | rs232_send_byte(port, b[i]); 54 | } 55 | } -------------------------------------------------------------------------------- /api/files.h: -------------------------------------------------------------------------------- 1 | #ifndef FILES_H 2 | #define FILES_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | #define MAX_PATH 255 11 | 12 | enum file_flags 13 | { 14 | IS_DIR = 0x01u, 15 | IS_READONLY = 0x02u, 16 | DRIVER_RESERVED = 0xFFFF0000u 17 | }; 18 | 19 | enum file_mode 20 | { 21 | FILE_READ = 0x01, 22 | FILE_WRITE = 0x02, 23 | FILE_CREATE = 0x08 24 | }; 25 | 26 | typedef uint64_t file_size_t; 27 | 28 | typedef struct 29 | { 30 | file_size_t size; 31 | uint32_t flags; 32 | time_t time_created; 33 | time_t time_modified; 34 | size_t full_path_len; 35 | char full_path[MAX_PATH]; 36 | } file_info; 37 | 38 | #ifdef __cplusplus 39 | } 40 | 41 | #include 42 | #include 43 | #include 44 | #include 45 | 46 | constexpr bool filesystem_names_identical(std::string_view a, std::string_view b) 47 | { 48 | if(a.size() != b.size()) 49 | return false; 50 | return std::equal(a.cbegin(), a.cend(), b.cbegin(), [](char c_a, char c_b) { 51 | return toupper(c_a) == toupper(c_b); 52 | }); 53 | } 54 | 55 | inline std::string filesystem_create_path(std::string_view dir, 56 | std::string_view name) 57 | { 58 | using namespace std::literals; 59 | 60 | if(name == "."sv) 61 | return std::string{dir}; 62 | else if(name == ".."sv) 63 | { 64 | auto slash = dir.find_last_of('/'); 65 | 66 | return std::string{dir.substr(0, slash)}; 67 | } 68 | else 69 | return (std::string{dir} + '/').append(name); 70 | } 71 | 72 | #endif 73 | 74 | #endif -------------------------------------------------------------------------------- /kernel/interrupt.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | [extern idtp] 3 | 4 | global idt_load 5 | idt_load: 6 | lidt [idtp] 7 | sti ;!!!!!!!!!!!!!!!!!THIS ENABLES IRQS DON'T FORGET!!!!!!!!!!!!!!!!!!!!! 8 | ret 9 | 10 | ;make 32 new global isrs 11 | %assign i 0 12 | %rep 32 13 | global isr %+ i 14 | %assign i i+1 15 | %endrep 16 | 17 | %macro isr0_7 1 ;isrs 0-7 will use this definition 18 | isr%1: 19 | cli 20 | push byte 0 21 | push byte %1 22 | jmp isr_common_stub 23 | %endmacro 24 | 25 | %assign i 0 ;define the first 8 isrs 26 | %rep 8 27 | isr0_7 i 28 | %assign i i+1 29 | %endrep 30 | 31 | %macro isr8_31 1 ;isrs 8-31 will use this definition 32 | isr%1: 33 | cli 34 | push byte %1 35 | jmp isr_common_stub 36 | %endmacro 37 | 38 | %assign i 8 ;define the next 24 isrs 39 | %rep 24 40 | isr8_31 i 41 | %assign i i+1 42 | %endrep 43 | 44 | ; We call a C function in here. We need to let the assembler know 45 | ; that '_fault_handler' exists in another file 46 | extern fault_handler 47 | 48 | ; This is our common ISR stub. It saves the processor state, sets 49 | ; up for kernel mode segments, calls the C-level fault handler, 50 | ; and finally restores the stack frame. 51 | isr_common_stub: 52 | pusha 53 | push ds 54 | push es 55 | push fs 56 | push gs 57 | mov ax, ss 58 | mov ds, ax 59 | mov es, ax 60 | ;mov fs, ax 61 | ;mov gs, ax 62 | mov eax, esp 63 | push eax 64 | call fault_handler 65 | pop eax 66 | pop gs 67 | pop fs 68 | pop es 69 | pop ds 70 | popa 71 | add esp, 8 72 | ;sti 73 | iret 74 | -------------------------------------------------------------------------------- /boot/memmap.asm: -------------------------------------------------------------------------------- 1 | [bits 16] 2 | 3 | getmem: ;low memory in KB is stored in ax, upper memory in bx and 32 bit memory in cx in blocks of 64k 4 | getuppermemoryxe801: 5 | ;xor dx, dx ;set dx to 0 6 | xor cx, cx ;set cx to 0 7 | 8 | mov ax, 0xe801 ;set up the ax for the BIOS call 9 | call int15_check_valid 10 | jcxz .useax ;if cx is 0 then try ax 11 | mov ax, cx ;ax contains the number of KB between 1 and 16 MB 12 | ;mov cx, dx ;bx contains the number of 64k blocks between 16 MB and 4 GB 13 | .useax: 14 | cmp ax, 0x3c00 ;sanity check, we shouldn't be getting more than 15 MB 15 | jg getuppermemoryx88 ;jump if not sane 16 | test ax, ax 17 | jnz done_high ;raise an error if no memory is returned 18 | 19 | getuppermemoryx88: 20 | clc 21 | mov ax, 0x8800 ;set up the ax for the BIOS call 22 | call int15_check_valid 23 | 24 | done_high: 25 | 26 | mov word [MULTIBOOT_OFFSET + multiboot_info.memoryHi], ax 27 | 28 | getlowmemory: 29 | clc 30 | int 0x12 ;call BIOS interrupt 31 | jnc .finish ;handle general error 32 | xor ax, ax ;signal an error by getting no memoru 33 | .finish: 34 | mov word [MULTIBOOT_OFFSET + multiboot_info.memoryLo], ax 35 | ret 36 | 37 | ;calls int 15 then checks the result for validity 38 | int15_check_valid: 39 | int 0x15 40 | jc .memerror ;handle general error 41 | cmp ah, 0x86 42 | je .memerror ;raise an error if the BIOS doesn't support the function 43 | cmp ah, 0x80 44 | je .memerror ;raise an error if the our command was invalid 45 | ret 46 | .memerror: 47 | xor ax, ax ;return 0 to let us know the shit hit the fan 48 | ret -------------------------------------------------------------------------------- /kernel/display.h: -------------------------------------------------------------------------------- 1 | #ifndef DISPLAY_H 2 | #define DISPLAY_H 3 | #ifdef __cplusplus 4 | 5 | #include 6 | 7 | extern "C" { 8 | #endif 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | void print_string_len(const char* str, size_t length); 17 | 18 | typedef struct mode_list mode_list; 19 | 20 | struct display_driver 21 | { 22 | bool (*set_mode)(size_t index); 23 | 24 | uint8_t* (*get_framebuffer)(); 25 | 26 | void (*set_display_offset)(size_t offset, bool on_retrace); 27 | 28 | //text mode funcs 29 | size_t(*get_cursor_offset)(); 30 | void (*set_cursor_offset)(size_t offset); 31 | void (*set_cursor_visible)(bool visible); 32 | 33 | const display_mode* available_modes; 34 | size_t num_modes; 35 | }; 36 | 37 | typedef struct display_driver display_driver; 38 | 39 | void display_add_driver(const display_driver* d, bool use_as_default); 40 | 41 | SYSCALL_HANDLER int set_cursor_offset(size_t offset); 42 | SYSCALL_HANDLER int set_display_mode(const display_mode* requested, display_mode* actual); 43 | SYSCALL_HANDLER int get_display_mode(int index, display_mode* result); 44 | SYSCALL_HANDLER uint8_t* map_display_memory(void); 45 | SYSCALL_HANDLER int set_display_offset(size_t offset, int on_retrace); 46 | 47 | #ifdef __cplusplus 48 | } 49 | 50 | void print_string(char c); 51 | void print_string(std::string_view str); 52 | 53 | template 54 | inline void print_strings(Args&&... args) 55 | { 56 | (print_string(std::forward(args)), ...); 57 | } 58 | 59 | 60 | #endif 61 | #endif -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Jake S. Del Mastro 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /api/keyboard.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | char vk_to_ascii[NUM_VIRTUAL_KEYS * 2] = { 4 | '\0','\b','\t','\n','\0','\0','\0','\0','\0','\0',' ', 5 | '\0','\0','\0','\0','\0','a','b','c','d','e','f','g', 6 | 'h','i','j','k','l','m','n','o','p','q','r','s','t', 7 | 'u','v','w','x','y','z','\0','0','1','2','3','4','5', 8 | '6','7','8','9','/','*','-','+','\n','.','`','0','1', 9 | '2','3','4','5','6','7','8','9','-','=',',','.','/', 10 | ';','\'','[',']','\\','\0','\0','\0','\0','\0','\0', 11 | '\0','\0','\0','\0','\0','\0','\x1b','\0','\0','\0', 12 | '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', 13 | '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', 14 | '\0','\0','\0','\0','\0','\0','\0','\0','\0', 15 | //shifted symbols 16 | '\0','\b','\t','\n','\0','\0','\0','\0','\0','\0',' ', 17 | '\0','\0','\0','\0','\0','A','B','C','D','E','F','G', 18 | 'H','I','J','K','L','M','N','O','P','Q','R','S','T', 19 | 'U','V','W','X','Y','Z','\0','0','1','2','3','4','5', 20 | '6','7','8','9','/','*','-','+','\n','.','~',')','!', 21 | '@','#','$','%','^','&','*','(','_','+','<','>','?', 22 | ':','\"','{','}','|','\0','\0','\0','\0','\0','\0', 23 | '\0','\0','\0','\0','\0','\0','\x1b','\0','\0','\0', 24 | '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', 25 | '\0','\0','\0','\0','\0','\0','\0','\0','\0','\0','\0', 26 | '\0','\0','\0','\0','\0','\0','\0','\0','\0' }; 27 | 28 | 29 | char get_ascii_from_vk(key_type k) 30 | { 31 | if (k < NUM_VIRTUAL_KEYS && get_keystate(k)) 32 | { 33 | if (get_keystate(VK_LSHIFT) || get_keystate(VK_RSHIFT)) 34 | { 35 | k += NUM_VIRTUAL_KEYS; 36 | } 37 | return vk_to_ascii[k]; 38 | } 39 | 40 | return '\0'; 41 | } -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | # Format Style Options - Created with Clang Power Tools 2 | --- 3 | AccessModifierOffset: -4 4 | AlignConsecutiveAssignments: Consecutive 5 | AlignOperands: Align 6 | AllowAllConstructorInitializersOnNextLine: true 7 | AllowShortBlocksOnASingleLine: Empty 8 | AllowShortFunctionsOnASingleLine: None 9 | AllowShortLoopsOnASingleLine: false 10 | BasedOnStyle: Google 11 | BinPackArguments: true 12 | BinPackParameters: true 13 | BraceWrapping: 14 | AfterCaseLabel: true 15 | AfterClass: true 16 | AfterControlStatement: true 17 | AfterEnum: true 18 | AfterFunction: true 19 | AfterNamespace: true 20 | AfterObjCDeclaration: true 21 | AfterStruct: true 22 | AfterUnion: true 23 | AfterExternBlock: true 24 | BeforeCatch: false 25 | BeforeElse: true 26 | IndentBraces: false 27 | SplitEmptyFunction: false 28 | SplitEmptyRecord: false 29 | SplitEmptyNamespace: false 30 | BeforeLambdaBody: false 31 | BeforeWhile: false 32 | BreakBeforeBraces: Allman 33 | BreakBeforeTernaryOperators: true 34 | BreakConstructorInitializers: BeforeComma 35 | BreakStringLiterals: false 36 | ColumnLimit: 80 37 | DeriveLineEnding: false 38 | DerivePointerAlignment: false 39 | EmptyLineBeforeAccessModifier: Leave 40 | FixNamespaceComments: false 41 | IncludeBlocks: Preserve 42 | IndentCaseLabels: false 43 | IndentPPDirectives: AfterHash 44 | IndentRequires: true 45 | IndentWidth: 4 46 | MaxEmptyLinesToKeep: 2 47 | ObjCBlockIndentWidth: 4 48 | PenaltyBreakBeforeFirstCallParameter: 100000 49 | PenaltyReturnTypeOnItsOwnLine: 60 50 | ReflowComments: false 51 | SortIncludes: false 52 | SpaceAfterTemplateKeyword: false 53 | SpaceBeforeParens: Never 54 | SpacesBeforeTrailingComments: 1 55 | TabWidth: 4 56 | UseCRLF: false 57 | UseTab: Always 58 | ... 59 | -------------------------------------------------------------------------------- /kernel/interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef IDT_H 2 | #define IDT_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | typedef struct 13 | { 14 | uint32_t gs, fs, es, ds; // pushed the segs last 15 | uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // pushed by 'pusha' 16 | uint32_t int_no, err_code; // our 'push byte #' and ecodes do this 17 | uint32_t eip, cs, eflags, sp, ss; // pushed by the processor automatically 18 | } __attribute__((packed)) interrupt_info; 19 | 20 | #define IDT_INT_PRESENT 0x80 21 | #define IDT_INT_RING(r) ((r << 5) & 0x60) 22 | #define IDT_GATE_INT_32 0x0E 23 | 24 | #define IDT_HARDWARE_INTERRUPT (IDT_INT_PRESENT | IDT_INT_RING(0) | IDT_GATE_INT_32) 25 | #define IDT_SOFTWARE_INTERRUPT (IDT_INT_PRESENT | IDT_INT_RING(3) | IDT_GATE_INT_32) 26 | #define IDT_SEGMENT_KERNEL 0x08 27 | #define IDT_SEGMENT_USER 0x18 28 | 29 | typedef struct 30 | { 31 | uint32_t ip; 32 | uint32_t cs; 33 | uint32_t flags; 34 | uint32_t sp; 35 | uint32_t ss; 36 | } interrupt_frame; 37 | 38 | #define INTERRUPT_HANDLER __attribute__((interrupt)) 39 | 40 | typedef INTERRUPT_HANDLER void (irq_func)(interrupt_frame* r); 41 | 42 | inline INT_CALLABLE void setup_segs() 43 | { 44 | __asm__ volatile("push $0x30\npop %fs"); 45 | } 46 | 47 | INT_CALLABLE void acknowledge_irq(uint8_t irq); 48 | void interrupts_init(); 49 | void isr_install_handler(uint8_t vector, irq_func r, bool user); 50 | void isr_uninstall_handler(uint8_t irq); 51 | void irq_install_handler(uint8_t irq, irq_func r); 52 | void irq_uninstall_handler(uint8_t irq); 53 | void irq_enable(uint8_t irq, bool enabled); 54 | 55 | bool irq_is_requested(uint8_t irq); 56 | 57 | #ifdef __cplusplus 58 | } 59 | #endif 60 | #endif -------------------------------------------------------------------------------- /cpplib/include/char_traits.h: -------------------------------------------------------------------------------- 1 | #ifndef __CHAR_TRAITS_H 2 | #define __CHAR_TRAITS_H 3 | 4 | namespace std { 5 | template class char_traits; 6 | } 7 | 8 | template 9 | class std::char_traits 10 | { 11 | public: 12 | using char_type = _CharT; 13 | using int_type = unsigned long; 14 | using pos_type = size_t; 15 | using off_type = size_t; 16 | 17 | static constexpr void assign(char_type& c1, const char_type& c2) noexcept 18 | { 19 | c1 = c2; 20 | } 21 | 22 | static constexpr bool eq(const char_type& c1, const char_type& c2) noexcept 23 | { 24 | return c1 == c2; 25 | } 26 | 27 | static constexpr bool lt(const char_type& c1, const char_type& c2) noexcept 28 | { 29 | return c1 < c2; 30 | } 31 | 32 | static constexpr int compare(const char_type* s1, const char_type* s2, 33 | size_t n) 34 | { 35 | for(; n; --n, ++s1, ++s2) 36 | { 37 | if(lt(*s1, *s2)) return -1; 38 | if(lt(*s2, *s1)) return 1; 39 | } 40 | return 0; 41 | } 42 | 43 | static constexpr size_t length(const char_type* s) 44 | { 45 | size_t i = 0; 46 | while(!eq(s[i], char_type())) 47 | { 48 | ++i; 49 | } 50 | return i; 51 | } 52 | 53 | static constexpr const char_type* find(const char_type* s, size_t n, const char_type& a) 54 | { 55 | for(size_t i = 0; i < n; ++i) 56 | { 57 | if(eq(s[i], a)) 58 | return s + i; 59 | } 60 | return 0; 61 | } 62 | 63 | static constexpr char_type to_char_type(const int_type& __c) noexcept 64 | { 65 | return static_cast(__c); 66 | } 67 | 68 | static constexpr int_type to_int_type(const char_type& __c) noexcept 69 | { 70 | return static_cast(__c); 71 | } 72 | 73 | static constexpr bool eq_int_type(const int_type& __c1, const int_type& __c2) noexcept 74 | { 75 | return __c1 == __c2; 76 | } 77 | }; 78 | 79 | #endif -------------------------------------------------------------------------------- /drivers/formats/mbr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MBR_SIZE 512 7 | 8 | struct __attribute__((packed)) mbr_partition 9 | { 10 | uint8_t status; 11 | uint8_t chs_first_sector[3]; 12 | uint8_t type; 13 | uint8_t chs_last_sector[3]; 14 | uint32_t lba_first_sector; 15 | uint32_t sector_count; 16 | }; 17 | 18 | struct __attribute__((packed)) mbr_info 19 | { 20 | mbr_partition entries[4]; 21 | uint8_t signature[2]; 22 | }; 23 | 24 | struct __attribute__((packed)) mbr 25 | { 26 | uint8_t boot_code[446]; 27 | mbr_info data; 28 | }; 29 | 30 | static int mbr_read_partitions(filesystem_drive* d, filesystem_virtual_drive* base, size_t block_size) 31 | { 32 | mbr_info boot; 33 | filesystem_read_from_disk(d, 0, offsetof(mbr, data), (uint8_t*)&boot, sizeof(mbr_info)); 34 | 35 | int return_val = -1; 36 | 37 | if((boot.signature[0] == 0x55 || boot.signature[1] == 0xAA)) 38 | { 39 | //kinda a hack to ignore fat boot sectors 40 | uint8_t boot_code[3]; 41 | filesystem_read_from_disk(d, 0, 0, (uint8_t*)&boot_code, sizeof(boot_code)); 42 | if(boot_code[0] == 0xEB || boot_code[2] == 0x90) 43 | { 44 | return 0; 45 | } 46 | 47 | return_val = 0; 48 | 49 | for(size_t i = 0; i < 4; i++) 50 | { 51 | mbr_partition* p = &boot.entries[i]; 52 | if(p->sector_count != 0) 53 | { 54 | if(base) 55 | { 56 | base->first_block = p->lba_first_sector; 57 | base->num_blocks = p->sector_count; 58 | base = nullptr; 59 | } 60 | else 61 | { 62 | filesystem_add_virtual_drive(d, p->lba_first_sector, p->sector_count); 63 | } 64 | } 65 | } 66 | } 67 | 68 | return return_val; 69 | } 70 | 71 | extern "C" void mbr_init(void) 72 | { 73 | filesystem_add_partitioner(mbr_read_partitions); 74 | } -------------------------------------------------------------------------------- /drivers/ramdisk.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "ramdisk.h" 8 | 9 | typedef struct ramdisk_drive 10 | { 11 | uint8_t* base; 12 | size_t size; 13 | } ramdisk_drive; 14 | 15 | static ramdisk_drive init_disk = {nullptr, 0}; 16 | 17 | static void ramdisk_read_blocks(void* d, size_t block_number, uint8_t* buf, size_t num_bytes); 18 | static ramdisk_drive* ramdisk_get_drive(size_t index); 19 | 20 | static disk_driver ramdisk_driver = { 21 | ramdisk_read_blocks, 22 | nullptr, 23 | nullptr, 24 | nullptr 25 | }; 26 | 27 | static void ramdisk_read_blocks(void* drv_data, size_t offset, uint8_t* buf, size_t num_bytes) 28 | { 29 | ramdisk_drive* rd = (ramdisk_drive*)drv_data; 30 | 31 | if(offset < rd->size) 32 | { 33 | if(offset + num_bytes > rd->size) 34 | { 35 | printf("read overrun on ramdisk\n"); 36 | } 37 | 38 | memcpy(buf, rd->base + offset, num_bytes); 39 | } 40 | } 41 | 42 | static ramdisk_drive* ramdisk_get_drive(size_t index) 43 | { 44 | if(init_disk.base == nullptr) 45 | { 46 | uintptr_t rd_begin = boot_information.ramdisk_location; 47 | uintptr_t rd_end = rd_begin + boot_information.ramdisk_size; 48 | 49 | size_t rd_size = rd_end - rd_begin; 50 | 51 | uintptr_t rd_page_begin = rd_begin & ~(PAGE_SIZE - 1); 52 | uintptr_t rd_pages = memmanager_minimum_pages(rd_end - rd_page_begin); 53 | 54 | size_t rd_offset = rd_begin - rd_page_begin; 55 | 56 | init_disk.base = rd_offset + (uint8_t*)memmanager_map_to_new_pages(rd_page_begin, rd_pages, PAGE_PRESENT | PAGE_RW); 57 | init_disk.size = rd_size; 58 | } 59 | 60 | return &init_disk; 61 | } 62 | 63 | void ramdisk_init() 64 | { 65 | ramdisk_drive* drive = ramdisk_get_drive(0); 66 | filesystem_add_drive(&ramdisk_driver, drive, 1, drive->size); 67 | } 68 | -------------------------------------------------------------------------------- /cpplib/cppruntime.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | void* operator new(size_t size, std::align_val_t align) 7 | { 8 | return aligned_alloc(static_cast(align), size); 9 | } 10 | 11 | void* operator new[](size_t size, std::align_val_t align) 12 | { 13 | return aligned_alloc(static_cast(align), size); 14 | } 15 | 16 | void* operator new (size_t size) 17 | { 18 | return malloc(size); 19 | } 20 | 21 | void* operator new[](size_t size) 22 | { 23 | return malloc(size); 24 | } 25 | 26 | void operator delete(void* p) 27 | { 28 | free(p); 29 | } 30 | 31 | void operator delete[](void* p) 32 | { 33 | free(p); 34 | } 35 | 36 | template 37 | static constexpr size_t num_digits(T number) 38 | { 39 | size_t count = 0; 40 | do 41 | { 42 | number /= Radix; 43 | count++; 44 | } while(number != 0); 45 | return count; 46 | } 47 | 48 | template 49 | static std::string m_to_string(T value) requires(std::is_integral_v) 50 | { 51 | std::string str; 52 | 53 | str.resize(num_digits(value)); 54 | auto it = str.end(); 55 | do 56 | { 57 | auto digit = static_cast((T)value % 10); 58 | *(--it) = digit + '0'; 59 | 60 | value = (T)value / 10; 61 | } while(value != 0); 62 | return str; 63 | } 64 | 65 | std::string std::to_string(int value) 66 | { 67 | return m_to_string(value); 68 | } 69 | 70 | std::string std::to_string(long value) 71 | { 72 | return m_to_string(value); 73 | } 74 | 75 | std::string std::to_string(long long value) 76 | { 77 | return m_to_string(value); 78 | } 79 | 80 | std::string std::to_string(unsigned value) 81 | { 82 | return m_to_string(value); 83 | } 84 | 85 | std::string std::to_string(unsigned long value) 86 | { 87 | return m_to_string(value); 88 | } 89 | 90 | std::string std::to_string(unsigned long long value) 91 | { 92 | return m_to_string(value); 93 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JSD/OS 2 | A small operating system for 32 bit x86 3 | 4 | ## What does JSD/OS stand for 5 | 6 | The actual meaning of the acronym is intentionally ambigous but might stand for one of "**J**ake **S**. **D**el Mastro **O**perating **S**ystem" or "**J**ake'**S** **D**isk **O**perating **S**ystem" or maybe even "**J**ake's **S**oftware **D**istribution **O**perating **S**ystem" or finally "**J**ava**S**cript is **D**isallowed **O**perating **S**ystem" 7 | 8 | ## Getting in Touch 9 | 10 | Check out the official discord server: https://discord.gg/cvK7hhSBgJ 11 | 12 | ## Goals 13 | 14 | - [x] Run on all almost x86 hardware since the 386sx 15 | - [x] Low Memory footprint < 1MB for a base system 16 | - [x] Highly modular, don't use what you don't need 17 | - [x] Mutitasking using CuFS 18 | - [ ] Zero Screen Tearing by default 19 | - [ ] SMP support 20 | - [ ] AMD64 version 21 | 22 | ## Non Goals 23 | 24 | - POSIX/Unix Compatibility 25 | - Fair scheduling 26 | 27 | ## Building 28 | 29 | requires clang (might work on gcc), nasm, meson, perl, objcopy & xorriso 30 | 31 | make sure you initialize your git submodules before building (``git submodule update --recursive --init``) 32 | 33 | ``` 34 | meson setup [build directory] --cross-file mesoncross.ini 35 | meson compile -C [build directory] 36 | ``` 37 | 38 | this will generate an iso file in the build directory you can run on hardware or your favourite emulator 39 | 40 | Most linux distros seems to have a pretty old version of meson in their repo, if your distro does not have a version that meets the minimum requirements, a workaround is to install via pip ```pip3 install --user meson``` 41 | 42 | ## FAQ 43 | 44 | ### What's with "EPSILON" in the release names? 45 | 46 | The greek letter Epsilon is often used in mathematics to represent a very small positive value approaching zero, this represents the status of the OS at this point in time, not much, but more than nothing. 47 | -------------------------------------------------------------------------------- /kernel/input.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "input.h" 5 | 6 | static bool virtual_keystates[NUM_VIRTUAL_KEYS]; 7 | 8 | #define INPUT_BUFFER_SIZE 64 9 | 10 | static volatile size_t input_buf_front = 0; 11 | static size_t input_buf_back = 0; 12 | static input_event input_buf[INPUT_BUFFER_SIZE]; 13 | 14 | static constinit sync::mutex input_waiting_mtx{}; 15 | static constinit sync::condition_variable input_waiting_cv{}; 16 | 17 | void handle_input_event(input_event e) 18 | { 19 | if(e.type == event_type::KEY_DOWN || e.type == event_type::KEY_UP) 20 | { 21 | bool down = (e.type == event_type::KEY_DOWN); 22 | 23 | virtual_keystates[e.data] = down; 24 | 25 | if(down && (e.data == VK_TAB) && (virtual_keystates[VK_RALT] || virtual_keystates[VK_LALT])) 26 | { 27 | //we hereby interrupt this process 28 | run_next_task(); 29 | return; 30 | } 31 | } 32 | 33 | input_buf[input_buf_front] = e; 34 | input_buf_front = (input_buf_front + 1) % INPUT_BUFFER_SIZE; 35 | 36 | input_waiting_cv.notify_one(); 37 | } 38 | 39 | static int do_get_input_event(input_event* e) 40 | { 41 | if(this_task_is_active()) 42 | { 43 | if(input_buf_back != input_buf_front) 44 | { 45 | *e = input_buf[input_buf_back]; 46 | input_buf_back = (input_buf_back + 1) % INPUT_BUFFER_SIZE; 47 | 48 | return 0; 49 | } 50 | 51 | return 1; 52 | } 53 | 54 | return -1; 55 | } 56 | 57 | SYSCALL_HANDLER int get_input_event(input_event* e, bool wait) 58 | { 59 | if(wait) 60 | { 61 | while(do_get_input_event(e) != 0) 62 | { 63 | sync::unique_lock l{input_waiting_mtx}; 64 | input_waiting_cv.wait(l); 65 | } 66 | return 0; 67 | } 68 | else 69 | { 70 | return do_get_input_event(e); 71 | } 72 | }; 73 | 74 | SYSCALL_HANDLER int get_keystate(key_type key) 75 | { 76 | if(key >= NUM_VIRTUAL_KEYS || !this_task_is_active()) 77 | { 78 | return 0; 79 | } 80 | return virtual_keystates[key]; 81 | } 82 | -------------------------------------------------------------------------------- /drivers/display/basic_text/basic_text.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //This code covers VGA or MDA text mode 5 | 6 | #define REG_SCREEN_CTRL 0x3D4 7 | #define REG_SCREEN_DATA 0x3D5 8 | 9 | #define VIDEOMEM 0xb8000 10 | 11 | static void basic_text_set_cursor_visibility(bool on) 12 | { 13 | outb(REG_SCREEN_CTRL, 0x0a); 14 | 15 | auto reg_val = inb(REG_SCREEN_DATA); 16 | 17 | outb(REG_SCREEN_DATA, on ? reg_val & ~0x20 : reg_val | 0x20); 18 | } 19 | 20 | static size_t basic_text_get_cursor_offset() 21 | { 22 | outb(REG_SCREEN_CTRL, 0x0f); 23 | uint16_t offset = inb(REG_SCREEN_DATA); 24 | outb(REG_SCREEN_CTRL, 0x0e); 25 | offset += inb(REG_SCREEN_DATA) << 8; 26 | return offset; 27 | } 28 | 29 | static void basic_text_set_cursor_offset(size_t offset) 30 | { 31 | // cursor LOW port to vga INDEX register 32 | outb(REG_SCREEN_CTRL, 0x0f); 33 | outb(REG_SCREEN_DATA, (uint8_t)(offset & 0xFF)); 34 | 35 | // cursor HIGH port to vga INDEX register 36 | outb(REG_SCREEN_CTRL, 0x0E); 37 | outb(REG_SCREEN_DATA, (uint8_t)((offset >> 8) & 0xFF)); 38 | } 39 | 40 | static uint8_t* basic_text_get_framebuffer() 41 | { 42 | return (uint8_t*)VIDEOMEM; 43 | } 44 | 45 | static display_mode actual_mode{ 46 | 80, 47 | 25, 48 | 80, 49 | 70, //refresh 50 | 16, //bpp 51 | FORMAT_TEXT_W_ATTRIBUTE, 52 | DISPLAY_TEXT_MODE, 53 | 80 * 25 * sizeof(uint16_t) 54 | }; 55 | 56 | static bool basic_text_set_mode(size_t index) 57 | { 58 | return true; 59 | } 60 | 61 | static void basic_text_set_display_offset(size_t offset, bool on_retrace) {} 62 | 63 | static display_driver basic_text = 64 | { 65 | basic_text_set_mode, 66 | 67 | basic_text_get_framebuffer, 68 | 69 | basic_text_set_display_offset, 70 | 71 | basic_text_get_cursor_offset, 72 | basic_text_set_cursor_offset, 73 | basic_text_set_cursor_visibility, 74 | 75 | &actual_mode, 1 76 | }; 77 | 78 | extern "C" void basic_text_init(void) 79 | { 80 | display_add_driver(&basic_text, true); 81 | } -------------------------------------------------------------------------------- /tools/buildiso.pl: -------------------------------------------------------------------------------- 1 | use File::Basename; 2 | use File::Path; 3 | use File::Copy; 4 | 5 | my $toolsdir = dirname(__FILE__); 6 | 7 | my $imgfile = ""; 8 | my $output_path = ""; 9 | 10 | my @args = (); 11 | 12 | my $skip_next = 0; 13 | 14 | foreach $argument (0 .. $#ARGV) 15 | { 16 | if($skip_next) 17 | { 18 | $skip_next = 0; 19 | next; 20 | } 21 | 22 | if($ARGV[$argument] eq '-o') 23 | { 24 | $imgfile = $ARGV[$argument + 1]; 25 | $skip_next = 1; 26 | next; 27 | } 28 | 29 | if($ARGV[$argument] eq '-d') 30 | { 31 | $output_path = $ARGV[$argument + 1]; 32 | $skip_next = 1; 33 | next; 34 | } 35 | 36 | push @args, $ARGV[$argument]; 37 | } 38 | 39 | $output_path = "$output_path/$imgfile.out"; 40 | 41 | rmtree $output_path; 42 | 43 | mkpath($output_path); 44 | 45 | foreach my $argument (@args) { 46 | 47 | my @parts = split('=', $argument); 48 | 49 | my $dir = dirname(@parts[0]); 50 | mkpath("$output_path/$dir"); 51 | copy(@parts[1], "$output_path/@parts[0]") 52 | } 53 | 54 | mkpath("$output_path/boot"); 55 | copy("$toolsdir/limine/LICENSE.md", "$output_path/boot/LICENSE.md"); 56 | copy("$toolsdir/limine/limine.sys", "$output_path/boot/limine.sys"); 57 | copy("$toolsdir/limine/limine-cd.bin", "$output_path/boot/limine-cd.bin"); 58 | copy("$toolsdir/limine/limine-cd-efi.bin", "$output_path/boot/limine-cd-efi.bin"); 59 | 60 | if ($^O eq "linux") { 61 | system("xorriso -as mkisofs -b boot/limine-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table --efi-boot boot/limine-cd-efi.bin -efi-boot-part --efi-boot-image --protective-msdos-label \"$output_path\" -o $imgfile"); 62 | } else { 63 | system("$toolsdir/xorriso/xorriso -as mkisofs -b boot/limine-cd.bin -no-emul-boot -boot-load-size 4 -boot-info-table --efi-boot boot/limine-cd-efi.bin -efi-boot-part --efi-boot-image --protective-msdos-label \"$output_path\" -o $imgfile"); 64 | } 65 | 66 | system("tools/limine-deploy \"$imgfile\""); -------------------------------------------------------------------------------- /clib/include/ctype.h: -------------------------------------------------------------------------------- 1 | #ifndef CTYPE_H 2 | #define CTYPE_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define CT_UP 0x01 // upper case 11 | #define CT_LOW 0x02 // lower case 12 | #define CT_DIG 0x04 // digit 13 | #define CT_CTL 0x08 // control 14 | #define CT_PUN 0x10 // punctuation 15 | #define CT_WHT 0x20 // white space (space/cr/lf/tab) 16 | #define CT_HEX 0x40 // hex digit 17 | #define CT_SP 0x80 // hard space (0x20) 18 | 19 | extern const char *_ctype; 20 | 21 | static inline int isalnum(int c) 22 | { 23 | return _ctype[(unsigned)(c)] & (CT_UP | CT_LOW | CT_DIG); 24 | } 25 | static inline int isalpha(int c) 26 | { 27 | return _ctype[(unsigned)(c)] & (CT_UP | CT_LOW); 28 | } 29 | static inline int iscntrl(int c) 30 | { 31 | return _ctype[(unsigned)(c)] & CT_CTL; 32 | } 33 | static inline int isdigit(int c) 34 | { 35 | return _ctype[(unsigned)c] & CT_DIG; 36 | } 37 | static inline int isgraph(int c) { 38 | return _ctype[(unsigned)(c)] & (CT_PUN | CT_UP | CT_LOW | CT_DIG); 39 | } 40 | static inline int islower(int c) { 41 | return (_ctype[(unsigned)(c)] & (CT_LOW)); 42 | } 43 | static inline int isprint(int c) { 44 | return (_ctype[(unsigned)(c)] & (CT_PUN | CT_UP | CT_LOW | CT_DIG | CT_SP)); 45 | } 46 | static inline int ispunct(int c) { 47 | return (_ctype[(unsigned)(c)] & (CT_PUN)); 48 | } 49 | static inline int isspace(int c) { 50 | return (_ctype[(unsigned)(c)] & (CT_WHT)); 51 | } 52 | static inline int isupper(int c) { 53 | return (_ctype[(unsigned)(c)] & (CT_UP)); 54 | } 55 | static inline int isxdigit(int c) { 56 | return (_ctype[(unsigned)(c)] & (CT_DIG | CT_HEX)); 57 | } 58 | static inline int isascii(int c) { 59 | return ((unsigned)(c) <= 0x7F); 60 | } 61 | static inline int toascii(int c) { 62 | return ((unsigned)(c) & 0x7F); 63 | } 64 | static inline int tolower(int c) { 65 | return (isupper(c) ? c + 'a' - 'A' : c); 66 | } 67 | static inline int toupper(int c) { 68 | return (islower(c) ? c + 'A' - 'a' : c); 69 | } 70 | 71 | #ifdef __cplusplus 72 | } 73 | #endif 74 | 75 | #endif -------------------------------------------------------------------------------- /kernel/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | //A syscall is accomplished by 14 | //putting the arguments into EAX, ECX, EDX, EDI, ESI 15 | //put the system call index into EBX 16 | //int 0x80 17 | //EAX has the return value 18 | 19 | SYSCALL_HANDLER int _empty() 20 | { 21 | return 0; 22 | } 23 | 24 | SYSCALL_HANDLER void diagnostic_print(const char* data, size_t len) 25 | { 26 | print_string_len(data, len); 27 | }; 28 | 29 | extern SYSCALL_HANDLER int iopl(int val); 30 | 31 | extern void handle_syscall(); 32 | 33 | const void* syscall_table[] = 34 | { 35 | syscall_find_file_by_path, 36 | syscall_open_file, 37 | syscall_close_file, 38 | syscall_read_file, 39 | exit_process, 40 | spawn_process, 41 | sysclock_get_master_time, 42 | syscall_get_ticks, 43 | sysclock_get_utc_offset, 44 | syscall_virtual_alloc, 45 | syscall_free_pages, 46 | syscall_unmap_user_pages, 47 | syscall_delete_file, 48 | syscall_open_file_handle, 49 | syscall_open_directory_handle, 50 | syscall_get_file_in_dir, 51 | syscall_get_file_info, 52 | syscall_get_root_directory, 53 | set_display_mode, 54 | map_display_memory, 55 | get_display_mode, 56 | syscall_close_directory, 57 | set_cursor_offset, 58 | get_keystate, 59 | physical_num_bytes_free, 60 | iopl, 61 | set_display_offset, 62 | get_input_event, 63 | syscall_write_file, 64 | syscall_dispose_file_handle, 65 | create_shared_buffer, 66 | open_shared_buffer, 67 | close_shared_buffer, 68 | map_shared_buffer, 69 | spawn_thread, 70 | exit_thread, 71 | yield_to, 72 | load_driver, 73 | diagnostic_print, 74 | get_process_info, 75 | set_tls_addr, 76 | }; 77 | 78 | const size_t num_syscalls = sizeof(syscall_table) / sizeof(void*); 79 | 80 | void setup_syscalls() 81 | { 82 | isr_install_handler(0x80, handle_syscall, false); 83 | } -------------------------------------------------------------------------------- /drivers/ata_cmd.h: -------------------------------------------------------------------------------- 1 | #ifndef ATA_CMD_H 2 | #define ATA_CMD_H 3 | 4 | #define ATA_CMD_READ_PIO 0x20u 5 | #define ATA_CMD_READ_PIO_EXT 0x24u 6 | #define ATA_CMD_READ_DMA 0xC8u 7 | #define ATA_CMD_READ_DMA_EXT 0x25u 8 | #define ATA_CMD_WRITE_PIO 0x30u 9 | #define ATA_CMD_WRITE_PIO_EXT 0x34u 10 | #define ATA_CMD_WRITE_DMA 0xCAu 11 | #define ATA_CMD_WRITE_DMA_EXT 0x35u 12 | #define ATA_CMD_CACHE_FLUSH 0xE7u 13 | #define ATA_CMD_CACHE_FLUSH_EXT 0xEAu 14 | #define ATA_CMD_PACKET 0xA0u 15 | #define ATA_CMD_IDENTIFY_PACKET 0xA1u 16 | #define ATA_CMD_IDENTIFY 0xECu 17 | 18 | #define ATAPI_CMD_READ 0xA8u 19 | #define ATAPI_CMD_EJECT 0x1Bu 20 | 21 | #define ATA_IDENT_DEVICETYPE 0u 22 | #define ATA_IDENT_CYLINDERS 2u 23 | #define ATA_IDENT_HEADS 6u 24 | #define ATA_IDENT_SECTORS 12u 25 | #define ATA_IDENT_SERIAL 20u 26 | #define ATA_IDENT_MODEL 54u 27 | #define ATA_IDENT_CAPABILITIES 98u 28 | #define ATA_IDENT_FIELDVALID 106u 29 | #define ATA_IDENT_MAX_LBA 120u 30 | #define ATA_IDENT_COMMANDSETS 164u 31 | #define ATA_IDENT_MAX_LBA_EXT 200u 32 | 33 | #define ATA_SR_BSY 0x80u // Busy 34 | #define ATA_SR_RDY 0x60u // Drive ready 35 | #define ATA_SR_DRDY 0x40u // Drive ready 36 | #define ATA_SR_DF 0x20u // Drive write fault 37 | #define ATA_SR_DSC 0x10u // Drive seek complete 38 | #define ATA_SR_DRQ 0x08u // Data request ready 39 | #define ATA_SR_CORR 0x04u // Corrected data 40 | #define ATA_SR_IDX 0x02u // Index 41 | #define ATA_SR_ERR 0x01u // Error 42 | 43 | #define ATA_ER_BBK 0x80u // Bad block 44 | #define ATA_ER_UNC 0x40u // Uncorrectable data 45 | #define ATA_ER_MC 0x20u // Media changed 46 | #define ATA_ER_IDNF 0x10u // ID mark not found 47 | #define ATA_ER_MCR 0x08u // Media change request 48 | #define ATA_ER_ABRT 0x04u // Command aborted 49 | #define ATA_ER_TK0NF 0x02u // Track 0 not found 50 | #define ATA_ER_AMNF 0x01u // No address mark 51 | 52 | #define ATA_SECTOR_SIZE 0x200u 53 | #define ATAPI_SECTOR_SIZE 0x800u 54 | 55 | #endif -------------------------------------------------------------------------------- /cpplib/include/array: -------------------------------------------------------------------------------- 1 | #ifndef STD_ARRAY_H 2 | #define STD_ARRAY_H 3 | 4 | extern "C" { 5 | #include 6 | } 7 | 8 | #include 9 | 10 | namespace std { 11 | template class array; 12 | 13 | template 14 | array(T, Args...)->array; 15 | }; 16 | 17 | template 18 | class std::array { 19 | public: 20 | using iterator = T*; 21 | using const_iterator = const T*; 22 | using size_type = size_t; 23 | 24 | constexpr iterator begin() 25 | { 26 | return ____data; 27 | } 28 | 29 | constexpr iterator end() 30 | { 31 | return ____data + N; 32 | } 33 | 34 | constexpr const_iterator begin() const noexcept 35 | { 36 | return ____data; 37 | } 38 | 39 | constexpr const_iterator end() const noexcept 40 | { 41 | return ____data + N; 42 | } 43 | 44 | constexpr const_iterator cbegin() const noexcept 45 | { 46 | return begin(); 47 | } 48 | 49 | constexpr const_iterator cend() const noexcept 50 | { 51 | return end(); 52 | } 53 | 54 | constexpr size_type size() const 55 | { 56 | return N; 57 | } 58 | 59 | constexpr size_type length() const 60 | { 61 | return size(); 62 | } 63 | 64 | constexpr T& at(size_type n) 65 | { 66 | return ____data[n]; 67 | } 68 | 69 | constexpr const T& at(size_type n) const 70 | { 71 | return ____data[n]; 72 | } 73 | 74 | constexpr T& operator[](size_type n) 75 | { 76 | return ____data[n]; 77 | } 78 | 79 | constexpr const T& operator[](size_type n) const 80 | { 81 | return ____data[n]; 82 | } 83 | 84 | constexpr T* data() noexcept 85 | { 86 | return ____data; 87 | } 88 | 89 | constexpr const T* data() const 90 | { 91 | return ____data; 92 | } 93 | 94 | constexpr void swap(array& v) noexcept 95 | { 96 | std::swap(____data, v.____data); 97 | } 98 | 99 | constexpr bool empty() 100 | { 101 | return N == 0; 102 | } 103 | 104 | constexpr const T& back() const 105 | { 106 | return ____data[N - 1]; 107 | } 108 | 109 | constexpr T& back() 110 | { 111 | return ____data[N - 1]; 112 | } 113 | 114 | T ____data[N]; 115 | }; 116 | #endif -------------------------------------------------------------------------------- /boot/disk.asm: -------------------------------------------------------------------------------- 1 | [bits 16] 2 | ; load cx sectors to ES:BX from boot drive at sector ax 3 | ; trashes di, dx 4 | ; next sector at es:bx 5 | disk_load: 6 | .MAIN: 7 | mov di, 20 ;try at most 5 times per sector 8 | .LOOP_HEAD: 9 | push ax ; save sector # 10 | push cx ; save # of sectors 11 | 12 | xor dx, dx ; prepare dx:ax for operation 13 | div word [bp_sectors_per_track] ; ax(trk) = ax(lba) / spt, dx(sec) = ax % spt 14 | inc dx ; adjust for sector 0 15 | mov cl, dl 16 | 17 | xor dx, dx ; prepare dx:ax for operation 18 | div word [bp_heads_per_cylinder] ; ax(cyl) = ax(trk) / hpc, dx(hd) = ax % hpc 19 | mov dh, dl 20 | 21 | ; al = cylinder, dh = head, cl = sector 22 | 23 | ; the track/cylinder number is a 10 bit value taken from the 2 high 24 | ; order bits of CL and the 8 bits in CH (low order 8 bits of track) 25 | mov ch, al 26 | shl ah, 6 ; shift the lowest bits of ah to the top 27 | and cl, 00111111b ; mask off the highest bits of cl 28 | or cl, ah ; and them together 29 | 30 | mov ax, 0x0201 ; BIOS read sector, 1 sector 31 | 32 | mov dl, BYTE [MULTIBOOT_OFFSET + multiboot_info.bootDevice] ; drive 33 | int 0x13 ; call bios interrupt 34 | 35 | pop cx ; restore # of sectors 36 | jnc .SUCCESS 37 | 38 | xor ax, ax ; BIOS reset disk; 39 | int 0x13 40 | dec di 41 | pop ax ; restore sector # 42 | jnz .LOOP_HEAD ; try reading again cause floppys sometimes fail randomly 43 | 44 | ret ; just give up and return if we haven't got it after 5 tries 45 | 46 | .SUCCESS: 47 | add bx, _bytes_per_sector ; queue next buffer 48 | jnc .FINISH ; if we exceeded the segment size 49 | mov ax, es 50 | add ax, 0x1000 ; increment the segment by 65536 bytes (4096) 51 | mov es, ax 52 | .FINISH: 53 | pop ax 54 | inc ax ; queue next sector 55 | loop .MAIN ; read next sector 56 | 57 | ret -------------------------------------------------------------------------------- /drivers/pit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include "pit.h" 8 | 9 | #define PIT_TICK_RATE 1193182 10 | 11 | //1 tick = 1 / 1193182 seconds 12 | static uint16_t pit_timer_divisor = 0xFFFF; 13 | static tick_t pit_time_elapsed_count = 0; 14 | 15 | static inline uint16_t read_pit_counter() 16 | { 17 | uint16_t val; 18 | 19 | __asm__ volatile("mov $0x00, %%al\n" 20 | "out %%al, $0x43\n" 21 | "in $0x40, %%al\n" 22 | "mov %%al, %%ah\n" 23 | "in $0x40, %%al\n" 24 | "xchg %%al, %%ah\n" 25 | : "=a"(val) 26 | : 27 | : ); 28 | return val; 29 | } 30 | 31 | tick_t pit_get_ticks() 32 | { 33 | int_lock l = lock_interrupts(); 34 | 35 | uint16_t pit_counter = read_pit_counter(); 36 | 37 | //checks if we missed an interrupt, if so just pretend we are measuring from precisely the tick before the interrupt would have happened 38 | //this is needed because: 39 | //if the PIT counter rolls over between the time when we disable interrupts and when we read it's value 40 | //then the timer will go backward and that is very bad 41 | if(irq_is_requested(0)) //check the interrupt request register for irq0 42 | { 43 | pit_counter = 0; 44 | } 45 | 46 | uint16_t count = (pit_timer_divisor - pit_counter); 47 | 48 | tick_t time_val = pit_time_elapsed_count + count; 49 | 50 | unlock_interrupts(l); 51 | 52 | return time_val; 53 | } 54 | 55 | //divisor in the range 0x01-0x10000 56 | static void pit_set_irq_period(uint32_t divisor) 57 | { 58 | outb(0x43, 0x36); // Set our command byte 0x36 59 | outb(0x40, (uint8_t)(divisor & 0xFF)); // Set low byte of divisor 60 | outb(0x40, (uint8_t)(divisor >> 8)); // Set high byte of divisor 61 | 62 | pit_timer_divisor = (uint16_t)(divisor - 1); 63 | } 64 | 65 | static INTERRUPT_HANDLER void pit_irq(interrupt_frame* r) 66 | { 67 | setup_segs(); 68 | 69 | pit_time_elapsed_count += pit_timer_divisor; 70 | 71 | acknowledge_irq(0); 72 | } 73 | 74 | tick_t pit_get_tick_rate() 75 | { 76 | return PIT_TICK_RATE; 77 | } 78 | 79 | void pit_init() 80 | { 81 | pit_set_irq_period(0xFFFF); //set our the PIT interrupt rate to minimum speed 82 | irq_install_handler(0, pit_irq); 83 | } -------------------------------------------------------------------------------- /kernel/sysclock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "sysclock.h" 10 | 11 | clock_t sysclock_get_date_time(struct tm* result); 12 | 13 | static volatile clock_t timer_ticks = 0; //This represents the number of PIT ticks since bootup 14 | //It should be used for timing NOT timekeeping 15 | 16 | static volatile time_t sysclock_begin_time = 0; //Epoch time, counting seconds since January 1st 1970 17 | //This will serve as our master system clock 18 | //It should be 64 bits and won't overflow until the end of time 19 | 20 | static int utc_offset = -5 * 3600; //5 hours in seconds 21 | 22 | struct tm sysclock_time; 23 | 24 | size_t sysclock_get_rate() 25 | { 26 | return static_cast(pit_get_tick_rate()); 27 | } 28 | 29 | clock_t sysclock_get_ticks() 30 | { 31 | return static_cast(pit_get_ticks()); 32 | } 33 | 34 | SYSCALL_HANDLER time_t sysclock_get_master_time() 35 | { 36 | return sysclock_begin_time + 37 | static_cast(pit_get_ticks() / pit_get_tick_rate()); 38 | } 39 | 40 | SYSCALL_HANDLER clock_t syscall_get_ticks(size_t* rate) 41 | { 42 | if(rate != NULL) 43 | { 44 | *rate = sysclock_get_rate(); 45 | } 46 | 47 | return sysclock_get_ticks(); 48 | } 49 | 50 | void sysclock_set_utc_offset(int offset) 51 | { 52 | utc_offset = offset; 53 | } 54 | 55 | int sysclock_get_utc_offset(void) 56 | { 57 | return utc_offset; 58 | } 59 | 60 | // Sets up the system clock 61 | void sysclock_init() 62 | { 63 | timer_ticks = 0; 64 | 65 | pit_init(); 66 | 67 | const auto tick_rate = pit_get_tick_rate(); 68 | 69 | const clock_t sample = cmos_get_date_time(&sysclock_time); //read time values from the RTC 70 | 71 | const time_t rtc_time = mktime(&sysclock_time); //Set our epoch time based on what we read from the RTC 72 | 73 | sysclock_begin_time = rtc_time - static_cast(sample / tick_rate); 74 | } 75 | 76 | void sysclock_sleep(size_t time, clock_unit unit) 77 | { 78 | clock_t begin = sysclock_get_ticks(); 79 | clock_t timer_end = begin 80 | + static_cast((time * pit_get_tick_rate()) / unit); 81 | while(sysclock_get_ticks() < timer_end); 82 | } 83 | 84 | -------------------------------------------------------------------------------- /tools/rdfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct __attribute__((packed)) rdfs_dir_entry 12 | { 13 | char name[8]; 14 | char extension[3]; 15 | uint8_t attributes; 16 | uint32_t offset; 17 | uint32_t size; 18 | time_t modified; 19 | time_t created; 20 | }; 21 | 22 | std::vector readFile(std::string in) 23 | { 24 | std::ifstream f(in, std::ios::binary); 25 | if(!f.is_open()) 26 | { 27 | std::cout << "RDFS error: cannot open " << in << "\n"; 28 | } 29 | return std::vector(std::istreambuf_iterator(f), std::istreambuf_iterator()); 30 | } 31 | 32 | int main(int argc, char** argv) 33 | { 34 | std::vector>> files; 35 | 36 | std::string output = "init.rfs"; 37 | 38 | for(int i = 1; i < argc; i++) 39 | { 40 | std::string arg = argv[i]; 41 | 42 | if(arg == "-o") 43 | { 44 | output = argv[++i]; 45 | } 46 | else 47 | { 48 | files.emplace_back(arg, readFile(arg)); 49 | } 50 | } 51 | 52 | std::ofstream f(output, std::ios::binary); 53 | if(!f.is_open()) 54 | { 55 | std::cout << "RDFS error: cannot open output file " << output << "\n"; 56 | } 57 | 58 | f.write("RDSK", 4); 59 | 60 | uint32_t num_files = files.size(); 61 | f.write((char*)&num_files, sizeof(uint32_t)); 62 | 63 | uint32_t offset = 4 + sizeof(uint32_t) + sizeof(rdfs_dir_entry) * num_files; 64 | for(auto&& fd : files) 65 | { 66 | rdfs_dir_entry e{{}, {}, 0, offset, (uint32_t)fd.second.size(), time(NULL), time(NULL)}; 67 | auto filename = std::filesystem::path(fd.first); 68 | auto name = filename.stem().string(); 69 | auto extension = filename.extension().string(); 70 | 71 | extension.erase(remove(extension.begin(), extension.end(), '.'), extension.end()); 72 | 73 | memset(e.name, 0, 8); 74 | memset(e.extension, 0, 3); 75 | memcpy(e.name, name.data(), std::min((size_t)8, name.size())); 76 | memcpy(e.extension, extension.data(), std::min((size_t)3, extension.size())); 77 | 78 | f.write((char*)&e, sizeof(rdfs_dir_entry)); 79 | offset += e.size; 80 | } 81 | 82 | 83 | for(auto&& fd : files) 84 | { 85 | f.write(fd.second.data(), fd.second.size()); 86 | } 87 | } -------------------------------------------------------------------------------- /common/display_mode.h: -------------------------------------------------------------------------------- 1 | #ifndef DISPLAY_MODE_H 2 | #define DISPLAY_MODE_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | 9 | enum display_format 10 | { 11 | FORMAT_DONT_CARE = 0, 12 | FORMAT_TEXT_W_ATTRIBUTE, 13 | FORMAT_INDEXED_BIT_PLANE, 14 | FORMAT_INDEXED_BYTE_PLANE, 15 | FORMAT_INDEXED_LINEAR, 16 | 17 | FORMAT_GRAYSCALE, 18 | 19 | FORMAT_BGR444, 20 | FORMAT_RGB332, 21 | FORMAT_RGB444, 22 | FORMAT_RGB555, 23 | FORMAT_BGR555, 24 | FORMAT_ARGB4444, 25 | FORMAT_RGBA4444, 26 | FORMAT_ABGR4444, 27 | FORMAT_BGRA4444, 28 | FORMAT_ARGB1555, 29 | FORMAT_RGBA5551, 30 | FORMAT_ABGR1555, 31 | FORMAT_BGRA5551, 32 | FORMAT_RGB565, 33 | FORMAT_BGR565, 34 | FORMAT_RGB24, 35 | FORMAT_BGR24, 36 | FORMAT_RGB888, 37 | FORMAT_RGBX8888, 38 | FORMAT_BGR888, 39 | FORMAT_BGRX8888, 40 | FORMAT_ARGB8888, 41 | FORMAT_RGBA8888, 42 | FORMAT_ABGR8888, 43 | FORMAT_BGRA8888, 44 | FORMAT_ARGB2101010, 45 | 46 | FORMAT_RGBA32 = FORMAT_RGBA8888, //RGBA byte array of color data, for the current platform 47 | FORMAT_ARGB32 = FORMAT_ARGB8888, //ARGB byte array of color data, for the current platform 48 | FORMAT_BGRA32 = FORMAT_BGRA8888, //BGRA byte array of color data, for the current platform 49 | FORMAT_ABGR32 = FORMAT_ABGR8888, //ABGR byte array of color data, for the current platform 50 | 51 | /* 52 | FORMAT_YV12, //planar mode : Y + V + U(3 planes) 53 | FORMAT_IYUV, //planar mode : Y + U + V(3 planes) 54 | FORMAT_YUY2, //packed mode : Y0 + U0 + Y1 + V0(1 plane) 55 | FORMAT_UYVY, //packed mode : U0 + Y0 + V0 + Y1(1 plane) 56 | 57 | FORMAT_YVYU, //packed mode : Y0 + V0 + Y1 + U0(1 plane) 58 | FORMAT_NV12, //planar mode : Y + U / V interleaved(2 planes) 59 | FORMAT_NV21, //planar mode : Y + V / U interleaved(2 planes) 60 | */ 61 | 62 | DISPLAY_MODE_INVALID 63 | }; 64 | 65 | typedef enum display_format display_format; 66 | 67 | enum display_flags { 68 | DISPLAY_TEXT_MODE = 0x01, 69 | DISPLAY_INDEXED = 0x02, 70 | DISPLAY_RGB = 0x04, 71 | DISPLAY_MONO = 0x08 72 | }; 73 | 74 | struct display_mode { 75 | size_t width; 76 | size_t height; 77 | size_t pitch; //in bytes 78 | size_t refresh; 79 | size_t bpp; 80 | display_format format; 81 | uint32_t flags; 82 | size_t buffer_size; 83 | }; 84 | 85 | typedef struct display_mode display_mode; 86 | 87 | #ifdef __cplusplus 88 | } 89 | #endif 90 | #endif -------------------------------------------------------------------------------- /clib/string.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | ;void* memset(void* ptr, int value, size_t num) 4 | global memset:function 5 | memset: 6 | push edi 7 | mov ecx, [esp + 16] 8 | mov al, [esp + 12] 9 | mov edi, [esp + 8] 10 | cld 11 | rep stosb 12 | mov eax, [esp + 8] 13 | pop edi 14 | ret 15 | 16 | ;void* memcpy(void* dest, const void* src, size_t num) 17 | global memcpy:function 18 | memcpy: 19 | push edi 20 | push esi 21 | mov ecx, [esp + 20] 22 | mov esi, [esp + 16] 23 | mov edi, [esp + 12] 24 | mov eax, ecx 25 | shr ecx, 2 ;convert bytes to dwords 26 | and eax, 3 ;whats the remainder? 27 | cld 28 | rep movsd ;copy as many dwords as possible 29 | mov ecx, eax 30 | rep movsb ;copy the rest of the bytes individually 31 | mov eax, [esp + 12] 32 | pop esi 33 | pop edi 34 | ret 35 | 36 | ;void* memmove(void* dest, const void* src, size_t num) 37 | ;global memmove 38 | ;memmove: 39 | ; push edi 40 | ; push esi 41 | ; mov ecx, [esp + 20] 42 | ; mov esi, [esp + 16] 43 | ; mov edi, [esp + 12] 44 | ; mov eax, ecx 45 | ; cmp esi, edi 46 | ; jl copy_backward 47 | ; shr ecx, 2 ;convert bytes to dwords 48 | ; and eax, 3 ;whats the remainder? 49 | ; cld 50 | ; rep movsd ;copy as many dwords as possible 51 | ; mov ecx, eax 52 | ; rep movsb ;copy the rest of the bytes individually 53 | ; mov eax, [esp + 12] 54 | ; pop esi 55 | ; pop edi 56 | ; ret 57 | ;copy_backward: 58 | ; add esi, ecx 59 | ; add edi, ecx 60 | ; shr ecx, 2 ;convert bytes to dwords 61 | ; and eax, 3 ;whats the remainder? 62 | ; std 63 | ; rep movsd ;copy as many dwords as possible 64 | ; mov ecx, eax 65 | ; rep movsb ;copy the rest of the bytes individually 66 | ; mov eax, [esp + 12] 67 | ; pop esi 68 | ; pop edi 69 | ; ret 70 | 71 | 72 | ;global memmove2 73 | memmove2: 74 | push edi 75 | push esi 76 | mov ecx, [esp + 20] 77 | mov esi, [esp + 16] 78 | mov edi, [esp + 12] 79 | mov eax, ecx 80 | cmp esi, edi 81 | jl copy_backward 82 | cld 83 | rep movsb 84 | mov eax, [esp + 12] 85 | pop esi 86 | pop edi 87 | ret 88 | copy_backward: 89 | add esi, ecx 90 | add edi, ecx 91 | ;shr ecx, 2 ;convert bytes to dwords 92 | ;and eax, 3 ;whats the remainder? 93 | std 94 | ;rep movsd 95 | ;mov ecx, eax 96 | rep movsb 97 | mov eax, edi 98 | pop esi 99 | pop edi 100 | ret -------------------------------------------------------------------------------- /kernel/bootstrap/boot_mapper.cpp: -------------------------------------------------------------------------------- 1 | //must compile with -fPIC 2 | #include 3 | #include 4 | 5 | alignas(4096) RECLAIMABLE_BSS static constinit uintptr_t pd[PAGE_TABLE_SIZE]; 6 | alignas(4096) RECLAIMABLE_BSS static constinit uintptr_t pt[PAGE_TABLE_SIZE]; 7 | 8 | RECLAIMABLE_BSS static uintptr_t pt_base = 0; 9 | 10 | #define PAGE_MASK (PAGE_SIZE - 1) 11 | 12 | extern "C" RECLAIMABLE void boot_mapper_remap_mem(uintptr_t virt, uintptr_t phys) 13 | { 14 | pt[(virt >> 12) & (PAGE_TABLE_SIZE - 1)] = phys | PAGE_PRESENT | PAGE_RW; 15 | } 16 | 17 | extern "C" RECLAIMABLE uintptr_t boot_mapper_map_mem(uintptr_t addr, 18 | size_t bytes) 19 | { 20 | auto aligned_addr = addr & ~PAGE_MASK; 21 | auto offset = addr & PAGE_MASK; 22 | 23 | size_t num_pages = memmanager_minimum_pages(offset + bytes); 24 | size_t pages_found = 0; 25 | 26 | for(size_t i = PAGE_TABLE_SIZE - 1; i > 0; --i) 27 | { 28 | if(pt[i] == 0) 29 | { 30 | if(pages_found == (num_pages - 1)) 31 | { 32 | for(uintptr_t page = i; 33 | page < (i + num_pages); page++) 34 | { 35 | pt[page] = aligned_addr | PAGE_PRESENT | PAGE_RW; 36 | aligned_addr += PAGE_SIZE; 37 | } 38 | __asm__ volatile( 39 | "mov %%cr3, %%eax\n" 40 | "mov %%eax, %%cr3" 41 | : 42 | : 43 | : "%eax", "memory"); 44 | return pt_base + offset + i * PAGE_SIZE; 45 | } 46 | ++pages_found; 47 | } 48 | else 49 | { 50 | pages_found = 0; 51 | } 52 | } 53 | 54 | return 0; 55 | } 56 | 57 | extern "C" RECLAIMABLE uintptr_t boot_remap_addresses(uintptr_t kernel_VM, 58 | size_t kernel_size, 59 | uintptr_t kernel_offset) 60 | { 61 | //the last entry in the page dir is mapped to the page dir 62 | pd[PAGE_TABLE_SIZE - 1] = (uintptr_t)pd | PAGE_PRESENT | PAGE_RW; 63 | 64 | pt_base = (kernel_VM >> 22) << 22; 65 | 66 | pd[kernel_VM >> 22] = (uintptr_t)pt | PAGE_PRESENT | PAGE_RW; 67 | 68 | auto pg_start = (kernel_VM >> 12) & (PAGE_TABLE_SIZE - 1); 69 | 70 | size_t num_k_pages = memmanager_minimum_pages(kernel_size); 71 | 72 | uintptr_t kernel_addr = kernel_offset & ~PAGE_MASK; 73 | 74 | for(size_t i = 0; i < num_k_pages; i++) 75 | { 76 | //uintptr_t* pd_entry = &pd[pg_start >> 22]; 77 | 78 | pt[pg_start] = kernel_addr | PAGE_PRESENT | PAGE_RW; 79 | 80 | kernel_addr += PAGE_SIZE; 81 | pg_start++; 82 | } 83 | 84 | return (uintptr_t)&pd[0]; 85 | } -------------------------------------------------------------------------------- /kernel/shared_mem.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | struct shared_buffer 9 | { 10 | std::string name; 11 | sync::mutex mtx; 12 | uintptr_t physical; 13 | size_t num_pages; 14 | size_t size; 15 | size_t num_refs; 16 | }; 17 | 18 | using shared_map = hash_map; 19 | using buf_map = hash_map; 20 | 21 | constinit sync::shared_mutex map_mtx; 22 | shared_map shared_buffers; 23 | 24 | SYSCALL_HANDLER uintptr_t create_shared_buffer(const char* name_data, size_t name_len, size_t size) 25 | { 26 | std::string_view name{name_data, name_len}; 27 | 28 | sync::unique_lock map_lock{map_mtx}; 29 | 30 | auto data = shared_buffers.emplace(name); 31 | if(!data) 32 | return 0; //could not create new buffer, likely already exists 33 | 34 | sync::lock_guard l{data->mtx}; 35 | 36 | map_lock.unlock(); 37 | 38 | data->name = name; 39 | data->size = size; 40 | data->num_pages = memmanager_minimum_pages(size); 41 | data->physical = physical_memory_allocate(data->num_pages * PAGE_SIZE, PAGE_SIZE); 42 | data->num_refs = 1; 43 | 44 | return !!(data->physical) ? (uintptr_t)data : 0; 45 | } 46 | 47 | SYSCALL_HANDLER uintptr_t open_shared_buffer(const char* name, size_t name_len) 48 | { 49 | sync::shared_lock map_lock{map_mtx}; 50 | 51 | if(auto data = shared_buffers.lookup(std::string_view{name, name_len})) 52 | { 53 | sync::lock_guard l{data->mtx}; 54 | 55 | data->num_refs++; 56 | 57 | return (uintptr_t)data; 58 | } 59 | 60 | return 0; //buffer does not exist 61 | } 62 | 63 | SYSCALL_HANDLER void close_shared_buffer(uintptr_t buf_handle) 64 | { 65 | auto data = (shared_buffer*)buf_handle; 66 | 67 | sync::unique_lock map_lock{map_mtx}; 68 | 69 | sync::lock_guard l{data->mtx}; 70 | 71 | if(--data->num_refs == 0) 72 | { 73 | physical_memory_free(data->physical, data->num_pages * PAGE_SIZE); 74 | 75 | shared_buffers.remove(data->name); 76 | } 77 | } 78 | 79 | SYSCALL_HANDLER void* map_shared_buffer(uintptr_t buf_handle, size_t size, page_flags_t flags) 80 | { 81 | auto data = (shared_buffer*)buf_handle; 82 | 83 | sync::lock_guard l{data->mtx}; 84 | 85 | if(data->size < size) 86 | return nullptr; 87 | 88 | return memmanager_map_to_new_pages(data->physical, 89 | memmanager_minimum_pages(size), 90 | PAGE_USER | PAGE_PRESENT | flags); 91 | } -------------------------------------------------------------------------------- /api/virtual_keys.h: -------------------------------------------------------------------------------- 1 | #ifndef VIRTUAL_KEYS_H 2 | #define VIRTUAL_KEYS_H 3 | 4 | #include 5 | 6 | typedef enum virtual_keycode 7 | { 8 | VK_NONE, 9 | VK_BACKSPACE, 10 | VK_TAB, 11 | VK_ENTER, 12 | VK_LSHIFT, 13 | VK_RSHIFT, 14 | VK_LCTRL, 15 | VK_RCTRL, 16 | VK_LALT, 17 | VK_RALT, 18 | VK_SPACE, 19 | VK_CAPS_LOCK, 20 | 21 | VK_LEFT, 22 | VK_UP, 23 | VK_RIGHT, 24 | VK_DOWN, 25 | 26 | VK_A, 27 | VK_B, 28 | VK_C, 29 | VK_D, 30 | VK_E, 31 | VK_F, 32 | VK_G, 33 | VK_H, 34 | VK_I, 35 | VK_J, 36 | VK_K, 37 | VK_L, 38 | VK_M, 39 | VK_N, 40 | VK_O, 41 | VK_P, 42 | VK_Q, 43 | VK_R, 44 | VK_S, 45 | VK_T, 46 | VK_U, 47 | VK_V, 48 | VK_W, 49 | VK_X, 50 | VK_Y, 51 | VK_Z, 52 | 53 | VK_NUMLOCK, 54 | VK_NUMPAD_0, 55 | VK_NUMPAD_1, 56 | VK_NUMPAD_2, 57 | VK_NUMPAD_3, 58 | VK_NUMPAD_4, 59 | VK_NUMPAD_5, 60 | VK_NUMPAD_6, 61 | VK_NUMPAD_7, 62 | VK_NUMPAD_8, 63 | VK_NUMPAD_9, 64 | VK_NUMPAD_DIVIDE, 65 | VK_NUMPAD_MULIPLY, 66 | VK_NUMPAD_MINUS, 67 | VK_NUMPAD_PLUS, 68 | VK_NUMPAD_ENTER, 69 | VK_NUMPAD_PERIOD, 70 | 71 | VK_BACKTICK, 72 | VK_0, 73 | VK_1, 74 | VK_2, 75 | VK_3, 76 | VK_4, 77 | VK_5, 78 | VK_6, 79 | VK_7, 80 | VK_8, 81 | VK_9, 82 | VK_MINUS, 83 | VK_EQUALS, 84 | 85 | VK_COMMA, 86 | VK_PERIOD, 87 | VK_SLASH, 88 | VK_SEMICOLON, 89 | VK_APOSTROPHE, 90 | VK_LSQR_BRACKET, 91 | VK_RSQR_BRACKET, 92 | VK_BACKSLASH, 93 | VK_LMETA, //win key mostly 94 | VK_RMETA, //win key mostly 95 | VK_MENU, //the least useful key on the keyboard 96 | 97 | VK_PRINT_SCREEN, 98 | VK_SCROLL_LOCK, 99 | VK_PAUSE, 100 | 101 | VK_INSERT, 102 | VK_HOME, 103 | VK_PAGE_UP, 104 | VK_DELETE, 105 | VK_END, 106 | VK_PAGE_DOWN, 107 | 108 | VK_ESCAPE, 109 | VK_F1, 110 | VK_F2, 111 | VK_F3, 112 | VK_F4, 113 | VK_F5, 114 | VK_F6, 115 | VK_F7, 116 | VK_F8, 117 | VK_F9, 118 | VK_F10, 119 | VK_F11, 120 | VK_F12, 121 | 122 | VK_MEDIA_PREVIOUS, 123 | VK_MEDIA_NEXT, 124 | VK_MEDIA_PLAY, 125 | VK_MEDIA_STOP, 126 | VK_VOLUME_UP, 127 | VK_VOLUME_DOWN, 128 | VK_MUTE, 129 | 130 | VK_CALC, 131 | 132 | VK_WWW, 133 | VK_WWW_SEARCH, 134 | VK_WWW_FWD, 135 | VK_WWW_BACK, 136 | VK_WWW_FAV, 137 | VK_WWW_REF, 138 | VK_WWW_STOP, 139 | 140 | VK_POWER, 141 | VK_SLEEP, 142 | VK_WAKE, 143 | VK_MYCOMP, 144 | VK_MAIL, 145 | VK_APPS, 146 | VK_MEDIA_SELECT, 147 | NUM_VIRTUAL_KEYS 148 | } virtual_keycode; 149 | 150 | typedef uint32_t key_type; 151 | 152 | #endif -------------------------------------------------------------------------------- /kernel/tss.h: -------------------------------------------------------------------------------- 1 | #ifndef TSS_H 2 | #define TSS_H 3 | 4 | #include 5 | 6 | struct __attribute__((packed)) tss 7 | { 8 | uint16_t lin; 9 | uint16_t reserved0; 10 | uint32_t esp0; 11 | uint16_t stack_seg; 12 | uint16_t reserved1; 13 | uint32_t r[23]; 14 | }; 15 | 16 | struct __attribute__((packed)) gdt_entry 17 | { 18 | uint16_t limit_lo; 19 | uint16_t base_lo; 20 | uint8_t base_mid; 21 | uint8_t access; 22 | uint8_t granularity; 23 | uint8_t base_hi; 24 | }; 25 | 26 | struct __attribute__((packed)) gdt 27 | { 28 | gdt_entry null = {0, 0, 0, 0, 0, 0}; 29 | gdt_entry code = {0xffff, 0x0000, 0x00, 0x9A, 0xCF, 0x00}; 30 | gdt_entry data = {0xffff, 0x0000, 0x00, 0x92, 0xCF, 0x00}; 31 | gdt_entry user_code = {0xffff, 0x0000, 0x00, 0xFA, 0xCF, 0x00}; 32 | gdt_entry user_data = {0xffff, 0x0000, 0x00, 0xF2, 0xCF, 0x00}; 33 | gdt_entry tls_data = {0xffff, 0x0000, 0x00, 0xF2, 0xCF, 0x00}; 34 | gdt_entry cpu_data = {0xffff, 0x0000, 0x00, 0x92, 0xCF, 0x00}; 35 | gdt_entry tss_data = {0, 0, 0, 0, 0, 0}; 36 | }; 37 | 38 | struct __attribute__((packed)) gdt_descriptor 39 | { 40 | uint16_t size; 41 | gdt* offset; 42 | }; 43 | 44 | struct __attribute__((packed)) saved_regs 45 | { 46 | uintptr_t esp; 47 | uintptr_t esp0; 48 | uintptr_t cr3; 49 | 50 | uint32_t tls_gdt_hi; 51 | uint16_t tls_base_lo; 52 | uint16_t unused; 53 | }; 54 | 55 | struct __attribute__((packed)) user_transition_stack_items 56 | { 57 | uint32_t ebp; 58 | uint32_t edi; 59 | uint32_t esi; 60 | uint32_t ebx; 61 | uint32_t flags; 62 | uint32_t eip; 63 | uint32_t cs; 64 | uintptr_t code_addr; 65 | uintptr_t stack_addr; 66 | }; 67 | 68 | constexpr saved_regs init_tcb_regs(uintptr_t stack_top, uintptr_t page_dir, 69 | uintptr_t tls_ptr) 70 | { 71 | return { 72 | .esp = stack_top - sizeof(user_transition_stack_items), 73 | .esp0 = stack_top, 74 | .cr3 = page_dir, 75 | .tls_gdt_hi = 76 | (tls_ptr & 0xFF000000) | 0x00CFF200 | ((tls_ptr >> 16) & 0xFF), 77 | .tls_base_lo = static_cast(tls_ptr & 0xFFFF), 78 | }; 79 | } 80 | 81 | struct TCB; 82 | 83 | struct __attribute__((packed)) arch_data 84 | { 85 | tss m_tss; 86 | gdt m_gdt; 87 | 88 | TCB* tcb; 89 | }; 90 | 91 | void setup_GDT(arch_data* cpu); 92 | void create_TSS(arch_data* cpu, uintptr_t stack_addr); 93 | void reload_TLS_seg(); 94 | uintptr_t get_TLS_seg_base(arch_data* n_cpu); 95 | uintptr_t get_CPU_seg_base(arch_data* n_cpu); 96 | void set_CPU_seg_base(arch_data* n_cpu, uintptr_t val); 97 | void set_TLS_seg_base(arch_data* n_cpu, uintptr_t val); 98 | 99 | #endif -------------------------------------------------------------------------------- /kernel/filesystem/util.h: -------------------------------------------------------------------------------- 1 | #ifndef FS_UTIL_H 2 | #define FS_UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct fs_chunks 9 | { 10 | size_t start_chunk; 11 | 12 | size_t start_offset; //offset to start in the first chunk 13 | size_t start_size; //size of the first chunk 14 | 15 | size_t num_full_chunks; //number of complete chunks 16 | 17 | size_t end_size; //size of the last chunk 18 | }; 19 | 20 | inline fs_chunks filesystem_chunkify_npow(size_t offset, size_t length, size_t chunk_size) 21 | { 22 | size_t first_chunk = offset / chunk_size; 23 | size_t start_offset = offset % chunk_size; 24 | 25 | size_t last_chunk = (offset + length) / chunk_size; 26 | size_t end_size = (offset + length) % chunk_size; 27 | 28 | if(first_chunk == last_chunk) 29 | { 30 | end_size = 0; //start and end are in the same chunk 31 | } 32 | 33 | size_t start_size = ((length - end_size) % chunk_size); 34 | size_t num_chunks = (length - (start_size + end_size)) / chunk_size; 35 | 36 | return {first_chunk, start_offset, start_size, num_chunks, end_size}; 37 | } 38 | 39 | inline fs_chunks filesystem_chunkify(file_size_t offset, size_t length, 40 | size_t chunk_size_mask, 41 | size_t chunk_size_log2) 42 | { 43 | size_t first_chunk = static_cast(offset >> chunk_size_log2); 44 | size_t start_offset = static_cast(offset) & chunk_size_mask; 45 | 46 | size_t last_chunk = static_cast((offset + length) >> chunk_size_log2); 47 | size_t end_size = static_cast(offset + length) & chunk_size_mask; 48 | 49 | if(first_chunk == last_chunk) 50 | { 51 | end_size = 0; //start and end are in the same chunk 52 | } 53 | 54 | size_t start_size = (length - end_size) & chunk_size_mask; 55 | size_t num_chunks = (length - (start_size + end_size)) >> chunk_size_log2; 56 | 57 | return {first_chunk, start_offset, start_size, num_chunks, end_size}; 58 | } 59 | 60 | inline fs_chunks filesystem_chunkify(size_t offset, size_t length, size_t chunk_size) 61 | { 62 | k_assert(std::has_single_bit(chunk_size)); 63 | return filesystem_chunkify(offset, length, chunk_size - 1, (size_t)std::countr_zero(chunk_size)); 64 | } 65 | 66 | #ifdef __cplusplus 67 | namespace fs 68 | { 69 | template 70 | T align_power_2(T x, T align) 71 | { 72 | k_assert(std::has_single_bit(align)); 73 | return x & ~(align - 1); 74 | } 75 | 76 | template 77 | T round_up(T x, T align) 78 | { 79 | return ((x + (align - 1)) / align) * align; 80 | } 81 | }; 82 | #endif 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /kernel/gdt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | extern cpu_state boot_cpu_state; 10 | 11 | RECLAIMABLE_DATA constinit gdt_descriptor gdt_descriptor_location = 12 | {sizeof(gdt) - 1, &boot_cpu_state.arch.m_gdt}; 13 | 14 | void load_TSS(uint16_t tss_seg) 15 | { 16 | asm volatile("ltr %0" : : "r"(tss_seg)); 17 | } 18 | 19 | constexpr uintptr_t get_seg_base(gdt_entry& e) 20 | { 21 | return (uintptr_t)(e.base_lo << 0) | 22 | (uintptr_t)(e.base_mid << 16) | 23 | (uintptr_t)(e.base_hi << 24); 24 | } 25 | 26 | uintptr_t get_TLS_seg_base(arch_data* n_cpu) 27 | { 28 | return get_seg_base(n_cpu->m_gdt.tls_data); 29 | } 30 | 31 | uintptr_t get_CPU_seg_base(arch_data* n_cpu) 32 | { 33 | return get_seg_base(n_cpu->m_gdt.cpu_data); 34 | } 35 | 36 | void reload_CPU_seg() 37 | { 38 | auto seg = (uint16_t)(offsetof(gdt, cpu_data)); 39 | asm volatile("mov %0, %%fs" : : "r"(seg)); 40 | } 41 | void set_seg_base(gdt_entry& e, uintptr_t val) 42 | { 43 | e.base_lo = val & 0xFFFF; 44 | e.base_mid = (val >> 16) & 0xFF; 45 | e.base_hi = (val >> 24) & 0xFF; 46 | } 47 | void set_CPU_seg_base(arch_data* n_cpu, uintptr_t val) 48 | { 49 | set_seg_base(n_cpu->m_gdt.cpu_data, val); 50 | reload_CPU_seg(); 51 | } 52 | 53 | void set_TLS_seg_base(arch_data* n_cpu, uintptr_t val) 54 | { 55 | set_seg_base(n_cpu->m_gdt.tls_data, val); 56 | reload_TLS_seg(); 57 | } 58 | 59 | void reload_TLS_seg() 60 | { 61 | auto seg = (uint16_t)(offsetof(gdt, tls_data)) | 3; 62 | asm volatile("mov %0, %%gs" : : "r"(seg)); 63 | } 64 | 65 | void setup_GDT(arch_data* cpu) 66 | { 67 | gdt_descriptor gdt_descriptor_location = {sizeof(gdt) - 1, &cpu->m_gdt}; 68 | 69 | asm volatile("lgdt %0" : : "m"(gdt_descriptor_location)); 70 | } 71 | 72 | void create_TSS(arch_data* cpu, uintptr_t stack_addr) 73 | { 74 | memset(&cpu->m_tss, 0, sizeof(tss)); 75 | 76 | cpu->m_tss.stack_seg = (uint16_t)(offsetof(gdt, data)); 77 | cpu->m_tss.esp0 = stack_addr; 78 | 79 | auto tss_addr = std::bit_cast(&cpu->m_tss); 80 | 81 | cpu->m_gdt.tss_data = { 82 | .limit_lo = sizeof(tss) & 0x0000FFFF, 83 | .base_lo = (uint16_t)(tss_addr & 0x0000FFFF), 84 | .base_mid = (uint8_t)((tss_addr >> 16) & 0xFF), 85 | .access = 0x89, 86 | .granularity = ((sizeof(tss) >> 16) & 0x0F) | 0x40, 87 | .base_hi = (uint8_t)((tss_addr >> 24) & 0xFF), 88 | }; 89 | 90 | uint16_t tss_seg = (uint16_t)(offsetof(gdt, tss_data)) | 3; 91 | 92 | load_TSS(tss_seg); 93 | } -------------------------------------------------------------------------------- /clib/stdlib.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #ifndef __KERNEL 6 | #include 7 | #else 8 | #include 9 | #include 10 | #include 11 | #endif 12 | 13 | #define _HAVE_UINTPTR_T 14 | 15 | #include "liballoc.h" 16 | 17 | int atoi(const char * str) 18 | { 19 | while(isspace(*str)) 20 | { 21 | str++; 22 | } 23 | 24 | int8_t sign = +1; 25 | 26 | if(*str == '-') 27 | { 28 | str++; 29 | sign = -1; 30 | } 31 | else if(*str == '+') 32 | { 33 | str++; 34 | } 35 | 36 | int n = 0; 37 | 38 | while(isdigit(*str)) 39 | { 40 | n = n * 10 + *str - '0'; 41 | str++; 42 | } 43 | 44 | return n*sign; 45 | } 46 | #ifdef __KERNEL 47 | //static volatile int_lock alloc_lock = 0; 48 | 49 | static constinit sync::mutex alloc_lock{}; 50 | static int liballoc_lock() 51 | { 52 | alloc_lock.lock(); 53 | return 0; 54 | } 55 | 56 | static int liballoc_unlock() 57 | { 58 | alloc_lock.unlock(); 59 | return 0; 60 | } 61 | #else 62 | static int liballoc_lock() 63 | { 64 | return 0; 65 | } 66 | 67 | static int liballoc_unlock() 68 | { 69 | return 0; 70 | } 71 | 72 | void exit(int status) 73 | { 74 | sys_exit(status); 75 | } 76 | 77 | int system(const char* command) 78 | { 79 | return 0; 80 | } 81 | 82 | #endif 83 | 84 | #ifdef __KERNEL 85 | #define MALLOC_FLAGS (PAGE_RW) 86 | #else 87 | #define MALLOC_FLAGS (PAGE_USER | PAGE_RW) 88 | #endif 89 | 90 | static void* liballoc_alloc(size_t n) 91 | { 92 | return alloc_pages(NULL, n, MALLOC_FLAGS); 93 | } 94 | 95 | static int liballoc_free(void* p, size_t n) 96 | { 97 | return free_pages(p, n); 98 | } 99 | 100 | static constinit heap_allocator library_allocator{ 101 | liballoc_lock, 102 | liballoc_unlock, 103 | liballoc_alloc, 104 | liballoc_free, 105 | }; 106 | 107 | constexpr size_t clib_default_align = 4; 108 | 109 | void* aligned_alloc(size_t alignment, size_t size) 110 | { 111 | return library_allocator.malloc_bytes(size, alignment); 112 | } 113 | 114 | void* malloc(size_t n) 115 | { 116 | return library_allocator.malloc_bytes(n, clib_default_align); 117 | } 118 | 119 | void* realloc(void* ptr, size_t size) 120 | { 121 | return library_allocator.realloc_bytes(ptr, size, clib_default_align); 122 | } 123 | 124 | void* calloc(size_t num, size_t size) 125 | { 126 | return library_allocator.calloc_bytes(num, size, clib_default_align); 127 | } 128 | 129 | void free(void* p) 130 | { 131 | return library_allocator.free_bytes(p); 132 | } -------------------------------------------------------------------------------- /kernel/memorymanager.h: -------------------------------------------------------------------------------- 1 | #ifndef _MEMORYMANAGER_H 2 | #define _MEMORYMANAGER_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | void memmanager_init(void); 14 | uintptr_t memmanager_get_physical(uintptr_t virtual_address); 15 | 16 | typedef uintptr_t page_flags_t; 17 | int memmanager_free_pages(void* page, size_t num_pages); 18 | void* memmanager_virtual_alloc(void* virtual_address, size_t n, page_flags_t flags); 19 | 20 | SYSCALL_HANDLER int syscall_free_pages(void* page, size_t num_pages); 21 | SYSCALL_HANDLER int syscall_unmap_user_pages(void* addr, size_t num_pages); 22 | SYSCALL_HANDLER void* syscall_virtual_alloc(void* virtual_address, size_t n, page_flags_t flags); 23 | 24 | int memmanager_unmap_pages(void* page, size_t num_pages); 25 | 26 | void memmanager_set_page_flags(void* virtual_address, size_t num_pages, page_flags_t flags); 27 | void* memmanager_map_to_new_pages(uintptr_t physical_address, size_t n, page_flags_t flags); 28 | 29 | uintptr_t memmanager_new_memory_space(); 30 | void memmanager_enter_memory_space(uintptr_t memspace); 31 | bool memmanager_destroy_memory_space(uintptr_t memspace); 32 | 33 | bool memmanager_handle_page_fault(page_flags_t err, uintptr_t page); 34 | 35 | inline uint32_t getcr2reg() 36 | { 37 | uint32_t cr2val; 38 | __asm__ __volatile__("mov %%cr2, %%eax\n" : "=a"(cr2val) : :); 39 | return (uint32_t)cr2val; 40 | } 41 | inline void set_page_directory(uintptr_t address) 42 | { 43 | __asm__ __volatile__("mov %0, %%cr3\n" : : "a"(address)); 44 | } 45 | 46 | inline void enable_paging(void) 47 | { 48 | __asm__ __volatile__( 49 | "mov %%cr0, %%eax\n" 50 | "or $0x80000001, %%eax\n" 51 | "mov %%eax, %%cr0\n" 52 | : 53 | : 54 | :); 55 | } 56 | 57 | inline void* get_page_directory() 58 | { 59 | uint32_t cr3val; 60 | __asm__ __volatile__("mov %%cr3, %%eax\n" : "=a"(cr3val) : :); 61 | return (void*)cr3val; 62 | } 63 | 64 | #ifdef __cplusplus 65 | enum page_flags : uintptr_t 66 | #else 67 | enum page_flags 68 | #endif 69 | { 70 | PAGE_PRESENT = 0x01u, 71 | PAGE_RW = 0x02u, 72 | PAGE_USER = 0x04u, 73 | 74 | // OS specific 75 | PAGE_RESERVED = 0x800u, // bit 11 76 | PAGE_MAP_ON_ACCESS = 0x400u, // bit 10 77 | 78 | PAGE_ALLOCATED = PAGE_RESERVED | PAGE_PRESENT 79 | }; 80 | 81 | #define PAGE_SIZE 0x1000u 82 | #define PAGE_TABLE_SIZE 0x400u 83 | 84 | inline size_t memmanager_minimum_pages(size_t bytes) 85 | { 86 | return (bytes + (PAGE_SIZE - 1)) / PAGE_SIZE; 87 | } 88 | 89 | 90 | #ifdef __cplusplus 91 | } 92 | #endif 93 | #endif -------------------------------------------------------------------------------- /kernel/bootstrap/boot_info.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | boot_info boot_information; 9 | 10 | extern uint32_t _boot_eax; 11 | extern uint32_t _boot_ebx; 12 | extern uintptr_t _kernel_location; 13 | 14 | extern void _BSS_END_; 15 | extern void _IMAGE_END_; 16 | extern void _KERNEL_START_; 17 | 18 | extern uintptr_t boot_mapper_map_mem(uintptr_t addr, size_t bytes); 19 | 20 | RECLAIMABLE void reserve_boot_mem() 21 | { 22 | if(boot_information.memmap_location) 23 | { 24 | uintptr_t memmap = boot_mapper_map_mem(boot_information.memmap_location, 25 | boot_information.memmap_size); 26 | 27 | for(uintptr_t addr = memmap; 28 | (uintptr_t)addr < (memmap + boot_information.memmap_size);) 29 | { 30 | multiboot_mmap_entry* entry = (multiboot_mmap_entry*)addr; 31 | if(entry->m_type == 1 && entry->m_length) 32 | { 33 | physical_memory_free((uintptr_t)entry->m_addr, 34 | (size_t)entry->m_length); 35 | } 36 | addr += entry->m_size + sizeof(uint32_t); 37 | } 38 | } 39 | else 40 | { 41 | physical_memory_free(0u, boot_information.low_memory * 1024); 42 | physical_memory_free(0x00100000u, boot_information.high_memory * 1024); 43 | 44 | //reserve BIOS & VRAM & EBDA 45 | physical_memory_reserve(0x80000, 0x100000 - 0x80000); 46 | } 47 | } 48 | 49 | RECLAIMABLE void parse_boot_info() 50 | { 51 | boot_information.kernel_location = _kernel_location; 52 | boot_information.kernel_size = 53 | (uintptr_t)&_IMAGE_END_ - (uintptr_t)&_KERNEL_START_; 54 | 55 | if(_boot_eax == 0x2badb002) //multiboot1 56 | { 57 | multiboot_info* info = 58 | (multiboot_info*)boot_mapper_map_mem(_boot_ebx, 59 | sizeof(multiboot_info)); 60 | multiboot_modules* modules = (multiboot_modules*) 61 | boot_mapper_map_mem(info->m_modsAddr, 62 | info->m_modsCount * sizeof(multiboot_modules)); 63 | 64 | uintptr_t rd_begin = modules[0].begin; 65 | uintptr_t rd_end = modules[0].end; 66 | 67 | boot_information.ramdisk_location = rd_begin; 68 | boot_information.ramdisk_size = rd_end - rd_begin; 69 | 70 | boot_information.high_memory = info->m_memoryHi; 71 | boot_information.low_memory = info->m_memoryLo; 72 | 73 | if(info->m_flags & (1 << 6)) 74 | { 75 | boot_information.memmap_location = info->m_mmap_addr; 76 | boot_information.memmap_size = info->m_mmap_length; 77 | } 78 | else 79 | { 80 | boot_information.memmap_location = 0; 81 | boot_information.memmap_size = 0; 82 | } 83 | } 84 | else if(_boot_eax == 0x36d76289) //multiboot2 85 | { 86 | assert(false); 87 | } 88 | else 89 | { 90 | assert(false); 91 | } 92 | } -------------------------------------------------------------------------------- /clib/include/stdio.h: -------------------------------------------------------------------------------- 1 | #ifndef STDIO_H 2 | #define STDIO_H 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | #include 8 | #include 9 | 10 | #define EOF 0x04 //ascii EOT character 11 | 12 | #ifndef NULL 13 | #define NULL (void*)0 14 | #endif 15 | 16 | #define FILENAME_MAX 256 17 | 18 | typedef size_t fpos_t; 19 | typedef struct FILE FILE; 20 | 21 | #ifndef __KERNEL 22 | extern FILE* stderr; 23 | extern FILE* stdout; 24 | extern FILE* stdin; 25 | 26 | size_t fwrite(const void* ptr, size_t size, size_t count, FILE* stream); 27 | size_t fread(void* ptr, size_t size, size_t count, FILE* stream); 28 | long int ftell(FILE* stream); 29 | int fflush(FILE* stream); 30 | 31 | #define SEEK_SET 0 32 | #define SEEK_CUR 1 33 | #define SEEK_END 2 34 | 35 | int fseek(FILE* stream, long int offset, int origin); 36 | 37 | int remove(const char* filename); 38 | int rename(const char* old_path, const char* new_path); 39 | 40 | int vfprintf(FILE* stream, const char* format, va_list arg); 41 | 42 | int vfscanf(FILE* __restrict stream, const char* __restrict format, va_list arg); 43 | int fscanf(FILE* __restrict stream, const char* __restrict format, ...); 44 | int sscanf(const char* __restrict buffer, const char* __restrict format, ...); 45 | int scanf(const char* __restrict format, ...); 46 | int vfscanf(FILE* __restrict stream, const char* __restrict format, 47 | va_list args); 48 | int vsscanf(const char* __restrict buffer, const char* __restrict format, 49 | va_list args); 50 | 51 | void set_stdout(size_t (*write)(const char* buf, size_t size, void* impl)); 52 | void set_stdin(size_t (*read)(char* buf, size_t size, void* impl)); 53 | void set_cwd(const char* cwd, size_t cwd_len); 54 | 55 | #endif 56 | 57 | void clearerr(FILE* stream); 58 | FILE* fopen(const char* filename, const char* mode); 59 | int fclose(FILE* stream); 60 | int feof(FILE* stream); 61 | int ferror(FILE* stream); 62 | //int fputc(int character, FILE* stream); 63 | int fputs(const char* str, FILE* stream); 64 | int fprintf(FILE* stream, const char* format, ...); 65 | int sprintf(char* s, const char * format, ...); 66 | int snprintf(char* s, size_t n, const char* format, ...); 67 | char *gets(char *str); //!blatantly unsafe function please do not use: BUFFER OVERFLOW!!! 68 | char *gets_s(char *str, size_t length); //!safe version of gets, if you provide a valid length it will not overflow 69 | int vsprintf(char *s, const char *format, va_list arg ); 70 | int vsnprintf(char *buffer, size_t n, const char* fmt, va_list args); 71 | int printf(const char* format, ...); 72 | int putchar(int character); 73 | int getchar(); 74 | //int getc(FILE* stream); 75 | int puts(const char* str); 76 | void perror(const char* str); 77 | //int fflush(FILE* stream); 78 | 79 | #ifdef __cplusplus 80 | } 81 | #endif 82 | #endif -------------------------------------------------------------------------------- /api/thread.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | struct tls_thread_block 9 | { 10 | tls_thread_block* self; 11 | task_id tid; 12 | void (*start_func)(); 13 | }; 14 | 15 | tls_thread_block* get_thread_ptr() 16 | { 17 | tls_thread_block* self; 18 | asm("mov %%gs:0, %0" : "=r"(self)); 19 | return self; 20 | } 21 | 22 | struct tls_data 23 | { 24 | size_t alloc_align; 25 | size_t alloc_size; 26 | size_t thread_block_offset; 27 | size_t local_image_offset; 28 | void* master_image_ptr; 29 | size_t image_size; 30 | }; 31 | 32 | tls_data gen_process_tls_data(const tls_image_data& img) 33 | { 34 | const auto align = std::max(img.alignment, alignof(tls_thread_block)); 35 | 36 | return tls_data{ 37 | .alloc_align = align, 38 | .alloc_size = 39 | align_addr(img.total_size, align) + sizeof(tls_thread_block), 40 | .thread_block_offset = align_addr(img.total_size, align), 41 | .local_image_offset = align_addr(img.total_size, img.alignment), 42 | .master_image_ptr = img.pointer, 43 | .image_size = img.image_size, 44 | }; 45 | } 46 | 47 | tls_data tls; 48 | 49 | void* create_tls_block(void (*func)()) 50 | { 51 | auto buffer = aligned_alloc(tls.alloc_align, tls.alloc_size); 52 | 53 | auto thread_block_location = 54 | std::bit_cast(buffer) + tls.thread_block_offset; 55 | 56 | auto tls_image_base = thread_block_location - tls.local_image_offset; 57 | 58 | auto thread_block = std::bit_cast(thread_block_location); 59 | 60 | thread_block->self = thread_block; 61 | thread_block->start_func = func; 62 | 63 | memcpy(std::bit_cast(tls_image_base), tls.master_image_ptr, 64 | tls.image_size); 65 | 66 | return thread_block; 67 | } 68 | 69 | void init_first_thread() 70 | { 71 | process_info p_info; 72 | get_process_info(&p_info); 73 | 74 | tls = gen_process_tls_data(p_info.tls); 75 | 76 | auto addr = create_tls_block(nullptr); 77 | 78 | set_tls_addr(addr); 79 | 80 | get_thread_ptr()->tid = p_info.pid; 81 | } 82 | 83 | void cleanup_thread_block(tls_thread_block* block) 84 | { 85 | auto buf_loc = (uintptr_t)block - tls.thread_block_offset; 86 | free(std::bit_cast(buf_loc)); 87 | } 88 | 89 | void cleanup_thread() 90 | { 91 | cleanup_thread_block(get_thread_ptr()->self); 92 | } 93 | 94 | task_id spawn_thread(void (*func)()) 95 | { 96 | return sys_spawn_thread( 97 | [](task_id this_thread) 98 | { 99 | get_thread_ptr()->tid = this_thread; 100 | get_thread_ptr()->start_func(); 101 | 102 | cleanup_thread(); 103 | 104 | exit_thread(0); 105 | }, 106 | create_tls_block(func)); 107 | } -------------------------------------------------------------------------------- /api/terminal/terminal.h: -------------------------------------------------------------------------------- 1 | #ifndef TERMINAL_H 2 | #define TERMINAL_H 3 | 4 | enum terminal_open_mode 5 | { 6 | TERMINAL_CREATE_NEW = 0, 7 | TERMINAL_CREATE_IF_NOT_FOUND, 8 | TERMINAL_OPEN_EXISTING 9 | }; 10 | 11 | #ifdef __cplusplus 12 | 13 | #include 14 | #include 15 | 16 | class terminal 17 | { 18 | public: 19 | static const int tab_size = 4; 20 | 21 | using open_mode = terminal_open_mode; 22 | 23 | terminal(const char* name, size_t name_len, size_t width, size_t height, open_mode mode); 24 | 25 | terminal(std::string_view name, size_t width, size_t height, open_mode mode) 26 | : terminal{name.data(), name.size(), width, height, mode} 27 | {} 28 | 29 | terminal(std::string_view name, 30 | open_mode mode = TERMINAL_CREATE_IF_NOT_FOUND) 31 | : terminal{name.data(), name.size(), 0, 0, mode} 32 | {} 33 | 34 | terminal(const terminal&) = delete; 35 | ~terminal(); 36 | 37 | void set_cursor_pos(size_t x, size_t y); 38 | void set_cursor_pos(size_t offset); 39 | 40 | void set_color(uint8_t bgr, uint8_t fgr, uint8_t bright); 41 | void set_ansi_color(uint8_t bgr, uint8_t fgr); 42 | 43 | size_t cursor_pos() const; 44 | 45 | void delete_chars(size_t num); 46 | 47 | void print(const char* str, size_t length); 48 | 49 | inline void print(std::string_view text) 50 | { 51 | print(text.data(), text.size()); 52 | } 53 | 54 | void print(char c); 55 | 56 | void print(int number); 57 | 58 | void print(unsigned int number); 59 | 60 | void print(char c, size_t num); 61 | 62 | uint8_t* get_underlying_buffer() const; 63 | 64 | void write_chars_at_pos(size_t x, size_t y, char chars, size_t num_chars); 65 | void write_chars_at_pos(size_t x, size_t y, const char* chars, 66 | size_t num_chars); 67 | void write_chars_at_pos(size_t x, size_t y, std::string_view text) 68 | { 69 | write_chars_at_pos(x, y, text.data(), text.size()); 70 | } 71 | 72 | void clear(); 73 | void clear_row(size_t row); 74 | void scroll_up(); 75 | 76 | int set_mode(size_t width, size_t height); 77 | 78 | size_t width() const; 79 | size_t height() const; 80 | 81 | private: 82 | class impl; 83 | impl* m_impl; 84 | }; 85 | 86 | extern "C" 87 | { 88 | #endif 89 | typedef enum terminal_open_mode terminal_open_mode; 90 | 91 | struct terminal_instance; 92 | typedef struct terminal_instance terminal_instance; 93 | 94 | terminal_instance* open_terminal(const char* name, size_t name_len, 95 | size_t width, size_t height, 96 | terminal_open_mode mode); 97 | 98 | void print_terminal(const char* buf, size_t size, 99 | terminal_instance* terminal); 100 | void close_terminal(terminal_instance* terminal); 101 | 102 | void reset_terminal_mode(terminal_instance* terminal); 103 | 104 | #ifdef __cplusplus 105 | } 106 | #endif 107 | 108 | #endif -------------------------------------------------------------------------------- /drivers/portio.h: -------------------------------------------------------------------------------- 1 | #ifndef PORTIO_H 2 | #define PORTIO_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | #define INT_CALLABLE __attribute__((no_caller_saved_registers)) 11 | 12 | static inline INT_CALLABLE uint8_t inb(uint16_t port) 13 | { 14 | uint8_t retval; 15 | __asm__ volatile ("inb %1, %0" 16 | : "=a"(retval) 17 | : "Nd"(port)); 18 | return retval; 19 | } 20 | 21 | static inline INT_CALLABLE void outb(uint16_t port, uint8_t val) 22 | { 23 | __asm__ volatile ("outb %0, %1" 24 | : 25 | : "a"(val), "Nd"(port)); 26 | } 27 | 28 | static inline INT_CALLABLE uint16_t inw(uint16_t port) 29 | { 30 | uint16_t retval; 31 | __asm__ volatile ("inw %1, %0" 32 | : "=a"(retval) 33 | : "Nd"(port)); 34 | return retval; 35 | } 36 | 37 | static inline INT_CALLABLE void outw(uint16_t port, uint16_t val) 38 | { 39 | __asm__ volatile ("outw %0, %1" 40 | : 41 | : "a"(val), "Nd"(port)); 42 | } 43 | 44 | static inline INT_CALLABLE uint32_t ind(uint16_t port) 45 | { 46 | uint32_t retval; 47 | __asm__ volatile ("inl %1, %0" 48 | : "=a"(retval) 49 | : "Nd"(port)); 50 | return retval; 51 | } 52 | 53 | static inline INT_CALLABLE void outd(uint16_t port, uint32_t val) 54 | { 55 | __asm__ volatile ("outl %0, %1" 56 | : 57 | : "a"(val), "Nd"(port)); 58 | } 59 | 60 | static inline INT_CALLABLE void outsb(uint16_t port, uint8_t* data, size_t size) 61 | { 62 | __asm__ volatile ("rep outsb" 63 | : "+S" (data), "+c" (size) 64 | : "d" (port)); 65 | } 66 | 67 | static inline INT_CALLABLE void insb(uint16_t port, uint8_t* data, size_t size) 68 | { 69 | __asm__ volatile ("rep insb" 70 | : "+D" (data), "+c" (size) 71 | : "d" (port) 72 | : "memory"); 73 | } 74 | 75 | static inline INT_CALLABLE void outsw(uint16_t port, uint16_t* data, size_t size) 76 | { 77 | __asm__ volatile ("rep outsw" 78 | : "+S" (data), "+c" (size) 79 | : "d" (port)); 80 | } 81 | 82 | static inline INT_CALLABLE void insw(uint16_t port, uint16_t* data, size_t size) 83 | { 84 | __asm__ volatile ("rep insw" 85 | : "+D" (data), "+c" (size) 86 | : "d" (port) 87 | : "memory"); 88 | } 89 | 90 | static inline INT_CALLABLE void outsd(uint16_t port, uint32_t* data, size_t size) 91 | { 92 | __asm__ volatile ("rep outsl" 93 | : "+S" (data), "+c" (size) 94 | : "d" (port)); 95 | } 96 | 97 | static inline INT_CALLABLE void insd(uint16_t port, uint32_t* data, size_t size) 98 | { 99 | __asm__ volatile ("rep insl" 100 | : "+D" (data), "+c" (size) 101 | : "d" (port) 102 | : "memory"); 103 | } 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | #endif -------------------------------------------------------------------------------- /clib/include/liballoc.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIBALLOC_H 2 | #define _LIBALLOC_H 3 | 4 | #include 5 | 6 | class __attribute__((visibility("hidden"))) heap_allocator 7 | { 8 | public: 9 | void* malloc_bytes(size_t req_size, size_t align); 10 | void free_bytes(void* ptr); 11 | void* calloc_bytes(size_t nobj, size_t size, size_t align); 12 | void* realloc_bytes(void* p, size_t size, size_t align); 13 | 14 | constexpr heap_allocator(int (*lock_func)(), 15 | int (*unlock_func)(), 16 | void* (*alloc_func)(size_t), 17 | int (*free_func)(void*, size_t)) 18 | : lock(lock_func), 19 | unlock(unlock_func), 20 | sys_alloc_pages(alloc_func), 21 | sys_free_pages(free_func) 22 | {} 23 | 24 | private: 25 | struct minor_block; 26 | struct major_block; 27 | 28 | struct major_block* l_memRoot = nullptr; ///< The root memory block acquired from the system. 29 | struct major_block* l_bestBet = nullptr; ///< The major with the most free memory. 30 | 31 | const size_t l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init. 32 | const size_t l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init. 33 | unsigned long long l_allocated = 0; ///< Running total of allocated memory. 34 | unsigned long long l_inuse = 0; ///< Running total of used memory. 35 | 36 | long long l_warningCount = 0; ///< Number of warnings encountered 37 | long long l_errorCount = 0; ///< Number of actual errors 38 | long long l_possibleOverruns = 0; ///< Number of possible overruns 39 | 40 | major_block* allocate_new_page(size_t size); 41 | 42 | // This function is supposed to lock the memory data structures. It 43 | // could be as simple as disabling interrupts or acquiring a spinlock. 44 | // It's up to you to decide. 45 | // 46 | // return 0 if the lock was acquired successfully. Anything else is 47 | // failure. 48 | int (* const lock)(); 49 | 50 | // This function unlocks what was previously locked by the liballoc_lock 51 | // function. If it disabled interrupts, it enables interrupts. If it 52 | // had acquiried a spinlock, it releases the spinlock. etc. 53 | // 54 | // return 0 if the lock was successfully released. 55 | int (* const unlock)(); 56 | 57 | // This is the hook into the local system which allocates pages. It 58 | // accepts an integer parameter which is the number of pages 59 | // required. The page size was set up in the liballoc_init function. 60 | // 61 | // return NULL if the pages were not allocated. 62 | // return A pointer to the allocated memory. 63 | void* (* const sys_alloc_pages)(size_t); 64 | 65 | // This frees previously allocated memory. The void* parameter passed 66 | // to the function is the exact same value returned from a previous 67 | // liballoc_alloc call. 68 | // 69 | // The integer value is the number of pages to free. 70 | // 71 | // return 0 if the memory was successfully freed. 72 | int (* const sys_free_pages)(void*, size_t); 73 | }; 74 | 75 | #endif 76 | 77 | 78 | -------------------------------------------------------------------------------- /common/util.h: -------------------------------------------------------------------------------- 1 | #ifndef JSD_OS_UTIL_H 2 | #define JSD_OS_UTIL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | template 11 | using smallest_uint = std::conditional_t< 12 | MaxVal <= std::numeric_limits::max(), unsigned char, 13 | std::conditional_t< 14 | MaxVal <= std::numeric_limits::max(), unsigned short, 15 | std::conditional_t< 16 | MaxVal <= std::numeric_limits::max(), unsigned int, 17 | std::conditional_t< 18 | MaxVal <= std::numeric_limits::max(), 19 | unsigned long, 20 | std::conditional_t< 21 | MaxVal <= std::numeric_limits::max(), 22 | unsigned long long, void>>>>>; 23 | 24 | //align must be a power of 2 25 | constexpr static inline uintptr_t align_addr(uintptr_t addr, size_t align) 26 | { 27 | assert(std::has_single_bit(align)); 28 | return (addr + (align - 1)) & ~(align - 1); 29 | } 30 | 31 | template 32 | requires(!std::is_array_v) 33 | class intrusive_ptr 34 | { 35 | public: 36 | constexpr intrusive_ptr() noexcept = default; 37 | constexpr intrusive_ptr(std::nullptr_t) noexcept 38 | { 39 | } 40 | 41 | template 42 | explicit intrusive_ptr(Args&&... args) : 43 | ctrl{new control_block{{std::forward(args)...}, 1}} 44 | { 45 | assert(ctrl); 46 | assert(ctrl->ref_count); 47 | } 48 | 49 | intrusive_ptr(const intrusive_ptr& s) : ctrl{s.ctrl} 50 | { 51 | if(ctrl) 52 | { 53 | assert(ctrl->ref_count); 54 | ++ctrl->ref_count; 55 | } 56 | } 57 | 58 | intrusive_ptr& operator=(const intrusive_ptr& s) noexcept 59 | { 60 | ctrl = s.ctrl; 61 | if(ctrl) 62 | { 63 | assert(ctrl->ref_count); 64 | ++ctrl->ref_count; 65 | } 66 | return *this; 67 | } 68 | 69 | intrusive_ptr& operator=(intrusive_ptr&& s) noexcept 70 | { 71 | std::swap(ctrl, s.ctrl); 72 | return *this; 73 | } 74 | 75 | intrusive_ptr(intrusive_ptr&& s) noexcept 76 | { 77 | ctrl = s.ctrl; 78 | s.ctrl = nullptr; 79 | 80 | if(ctrl) 81 | { 82 | assert(ctrl->ref_count); 83 | } 84 | } 85 | 86 | ~intrusive_ptr() 87 | { 88 | if(ctrl) 89 | { 90 | assert(ctrl->ref_count); 91 | if(--ctrl->ref_count == 0) 92 | { 93 | delete ctrl; 94 | } 95 | } 96 | } 97 | 98 | T& operator*() const noexcept 99 | { 100 | assert(ctrl); 101 | return ctrl->value; 102 | } 103 | 104 | T* operator->() const noexcept 105 | { 106 | assert(ctrl); 107 | return &ctrl->value; 108 | } 109 | 110 | explicit operator bool() const noexcept 111 | { 112 | return !!ctrl; 113 | } 114 | 115 | private: 116 | struct control_block 117 | { 118 | T value; 119 | size_t ref_count = 0; 120 | }; 121 | 122 | control_block* ctrl = nullptr; 123 | }; 124 | 125 | template 126 | T read_addr(uintptr_t addr) requires(std::is_trivially_copyable_v) 127 | { 128 | T value; 129 | memcpy(&value, (void*)addr, sizeof(T)); 130 | return value; 131 | } 132 | 133 | #endif -------------------------------------------------------------------------------- /apps/graphics.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | uint32_t from_rgb(uint8_t r, uint8_t g, uint8_t b) 7 | { 8 | return ((uint32_t)r << 16)| 9 | ((uint32_t)g << 8) | 10 | ((uint32_t)b); 11 | } 12 | 13 | void draw_gradient(size_t begin, size_t end, display_mode& actual, uint32_t* mem) 14 | { 15 | size_t ddpl = (actual.pitch / 4); 16 | size_t offset = 0; 17 | 18 | for(size_t y = begin; y < end; y++) 19 | { 20 | auto cy = y * 255 / (end - begin); 21 | 22 | for(size_t x = 0; x < actual.width; x++) 23 | { 24 | auto c = x * 255 / actual.width; 25 | 26 | mem[offset++] = 27 | from_rgb((uint8_t)c, (uint8_t)cy, (uint8_t)(255 - c)); 28 | } 29 | offset += ddpl - actual.width; 30 | } 31 | } 32 | 33 | void draw_fill(size_t x0, size_t y0, size_t w, size_t h, display_mode& actual, uint32_t* mem) 34 | { 35 | size_t ddpl = (actual.pitch / 4); 36 | size_t offset = y0 * ddpl + x0; 37 | uint32_t value = from_rgb(255, 255, 255); 38 | 39 | for(size_t y = 0; y < h; y++) 40 | { 41 | for(size_t x = 0; x < w; x++) 42 | { 43 | mem[offset++] = value; 44 | } 45 | offset += ddpl - w; 46 | } 47 | } 48 | 49 | terminal s_term{"terminal_1"}; 50 | 51 | int main(int argc, char** argv) 52 | { 53 | display_mode requested = { 54 | 800, 600, 55 | 0, 56 | 0, 57 | 32, 58 | FORMAT_ARGB32, 59 | 0, 60 | 0 61 | }; 62 | display_mode actual; 63 | if(set_display_mode(&requested, &actual) != 0) 64 | { 65 | s_term.set_mode(80, 25); 66 | s_term.print("Could not set graphics mode\n"); 67 | return 0; 68 | } 69 | 70 | auto mem = (uint32_t*)map_display_memory(); 71 | 72 | int cursor_x = 0, cursor_y = 0; 73 | 74 | size_t page_begin = 0; 75 | set_display_offset(page_begin, true); 76 | 77 | input_event e{}; 78 | while(!(e.type == KEY_DOWN && e.data == VK_ESCAPE)) 79 | { 80 | while(get_input_event(&e, false) == 0) 81 | { 82 | if(e.device_index == 0) 83 | { 84 | if(e.type == AXIS_MOTION) 85 | { 86 | if(e.control_index == 0) // x axis 87 | { 88 | cursor_x = (cursor_x + e.data); 89 | 90 | if(cursor_x < 0) 91 | cursor_x = 0; 92 | else if(cursor_x >= (actual.width - 32u)) 93 | cursor_x = (int)(actual.width - 32u); 94 | } 95 | else if(e.control_index == 1) // y axis 96 | { 97 | cursor_y = (cursor_y + e.data); 98 | 99 | if(cursor_y < 0) 100 | cursor_y = 0; 101 | else if(cursor_y >= (actual.height - 32u)) 102 | cursor_y = (int)(actual.height - 32u); 103 | } 104 | } 105 | } 106 | } 107 | 108 | if(page_begin == 0) 109 | { 110 | page_begin = (actual.height * actual.pitch); 111 | } 112 | else 113 | { 114 | page_begin = 0; 115 | } 116 | 117 | draw_gradient(0, actual.height, actual, mem + page_begin / 4); 118 | 119 | draw_fill((size_t)cursor_x, (size_t)cursor_y, 32, 32, actual, 120 | mem + page_begin / 4); 121 | 122 | set_display_offset(page_begin, true); 123 | } 124 | 125 | s_term.set_mode(80, 25); 126 | s_term.clear(); 127 | 128 | return 0; 129 | } -------------------------------------------------------------------------------- /drivers/formats/rdfs.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include "rdfs.h" 7 | 8 | static mount_status rdfs_mount_disk(filesystem_virtual_drive* fd) 9 | { 10 | if(fd->block_size > 1) 11 | { 12 | return DRIVE_NOT_SUPPORTED; 13 | } 14 | 15 | uint8_t magic[4]; 16 | filesystem_read(fd, 0, 0, &magic[0], sizeof(magic)); 17 | 18 | if(memcmp(magic, "RDSK", 4) == 0) 19 | { 20 | fd->root_dir = { 21 | .name = fd->root_name, 22 | .data = {sizeof(magic), fd->id, 0, IS_DIR}, 23 | .time_created = 0, 24 | .time_modified = 0, 25 | }; 26 | 27 | return MOUNT_SUCCESS; 28 | } 29 | return UNKNOWN_FILESYSTEM; 30 | } 31 | 32 | static fs_index rdfs_read(uint8_t* dest, fs_index location, file_size_t offset, 33 | size_t num_bytes, const file_data_block* file, 34 | const filesystem_virtual_drive* fd) 35 | { 36 | const size_t f_offset = static_cast(offset); 37 | filesystem_read(fd, location, f_offset, dest, num_bytes); 38 | return location + f_offset + num_bytes; 39 | } 40 | 41 | typedef struct 42 | { 43 | char name[8]; 44 | char extension[3]; 45 | uint8_t attributes; 46 | uint32_t offset; 47 | uint32_t size; 48 | time_t modified; 49 | time_t created; 50 | } __attribute__((packed)) rdfs_dir_entry; 51 | 52 | static std::string_view read_field(const char* field, size_t size) 53 | { 54 | std::string_view f(field, size); 55 | if(auto pos = f.find('\0'); pos != std::string_view::npos) 56 | { 57 | return f.substr(0, pos); 58 | } 59 | return f; 60 | } 61 | 62 | static void rdfs_read_dir(directory_stream* dest, const file_data_block* f, const filesystem_virtual_drive* fd) 63 | { 64 | fs_index location = f->location_on_disk; 65 | 66 | uint32_t num_files; 67 | filesystem_read(fd, location, 0, (uint8_t*)&num_files, sizeof(uint32_t)); 68 | 69 | fs_index disk_location = location + sizeof(uint32_t); 70 | for(size_t i = 0; i < num_files; i++) 71 | { 72 | rdfs_dir_entry entry; 73 | filesystem_read(fd, disk_location, 0, (uint8_t*)&entry, sizeof(rdfs_dir_entry)); 74 | disk_location += sizeof(rdfs_dir_entry); 75 | 76 | file_handle file; 77 | 78 | file.name = read_field(entry.name, 8); 79 | if(auto ext = read_field(entry.extension, 3); !ext.empty()) 80 | { 81 | file.name += '.'; 82 | file.name += ext; 83 | } 84 | 85 | file.dir_path = dest->full_path; 86 | 87 | file.time_created = entry.created; 88 | file.time_modified = entry.modified; 89 | 90 | uint32_t flags = 0; 91 | if(entry.attributes & IS_DIR) 92 | { 93 | flags |= IS_DIR; 94 | } 95 | 96 | file.data = { 97 | .location_on_disk = entry.offset, 98 | .disk_id = fd->id, 99 | .size = entry.size, 100 | .flags = flags 101 | }; 102 | 103 | dest->file_list.push_back(file); 104 | } 105 | } 106 | 107 | static filesystem_driver rdfs_driver = { 108 | rdfs_mount_disk, 109 | rdfs_read, 110 | nullptr, 111 | nullptr, 112 | rdfs_read_dir, 113 | nullptr, 114 | nullptr 115 | }; 116 | 117 | extern "C" void rdfs_init(void) 118 | { 119 | filesystem_add_driver(&rdfs_driver); 120 | } 121 | -------------------------------------------------------------------------------- /kernel/locks.cpp: -------------------------------------------------------------------------------- 1 | #include "locks.h" 2 | #include "task.h" 3 | 4 | #include 5 | #include 6 | 7 | using cas_type = decltype(lockable_val::value); 8 | 9 | #ifdef SYNC_HAS_CAS_FUNC 10 | static inline bool tas_aquire(uint8_t* l) 11 | { 12 | return __sync_val_compare_and_swap(l, 0, 1); 13 | } 14 | 15 | static inline void tas_release(uint8_t* l) 16 | { 17 | __atomic_store_n(l, 0, __ATOMIC_RELEASE); 18 | } 19 | 20 | template 21 | static inline int cas_func(lockable_val* ptr, T oldval, T newval) 22 | { 23 | return std::bit_cast( 24 | __sync_val_compare_and_swap(&ptr->value, 25 | std::bit_cast(oldval), 26 | std::bit_cast(newval))); 27 | } 28 | 29 | #else 30 | static inline bool tas_aquire(uint8_t* l) 31 | { 32 | return __sync_lock_test_and_set(l, 1); 33 | } 34 | 35 | static inline void tas_release(uint8_t* l) 36 | { 37 | __sync_lock_release(l); 38 | } 39 | 40 | static inline int_lock atomic_lock_aquire(lockable_val* ptr) 41 | { 42 | #ifndef EMULATE_CAS_W_TAS 43 | return lock_interrupts(); 44 | #else 45 | while(true) 46 | { 47 | int_lock l = lock_interrupts(); 48 | if(tas_aquire(&ptr->tas_lock) == 0) 49 | return l; 50 | unlock_interrupts(l); 51 | } 52 | #endif 53 | } 54 | 55 | static inline void atomic_lock_release(int_lock l, lockable_val* ptr) 56 | { 57 | #ifdef EMULATE_CAS_W_TAS 58 | tas_release(&ptr->tas_lock); 59 | #endif 60 | unlock_interrupts(l); 61 | } 62 | 63 | template 64 | static inline T cas_func(lockable_val* ptr, T oldval, T newval) 65 | { 66 | int_lock l = atomic_lock_aquire(ptr); 67 | 68 | T old_ptr_val = std::bit_cast(ptr->value); 69 | if(old_ptr_val == oldval) { ptr->value = std::bit_cast(newval); } 70 | 71 | atomic_lock_release(l, ptr); 72 | 73 | return old_ptr_val; 74 | } 75 | 76 | #endif 77 | 78 | static inline task_id do_try_lock_mutex(kernel_mutex* m, task_id my_pid) 79 | { 80 | return cas_func(&m->ownerPID, INVALID_TASK_ID, my_pid); 81 | } 82 | 83 | bool kernel_try_lock_mutex(kernel_mutex* m) 84 | { 85 | return do_try_lock_mutex(m, get_running_task_id()) == INVALID_TASK_ID; 86 | } 87 | 88 | void kernel_lock_mutex(kernel_mutex* m) 89 | { 90 | const auto my_pid = get_running_task_id(); 91 | while(true) 92 | { 93 | auto pid = do_try_lock_mutex(m, my_pid); 94 | if(pid == INVALID_TASK_ID) [[likely]] 95 | break; 96 | switch_to_task(pid); 97 | } 98 | } 99 | 100 | void kernel_unlock_mutex(kernel_mutex* m) 101 | { 102 | __atomic_store_n(&m->ownerPID.value, std::bit_cast(INVALID_TASK_ID), 103 | __ATOMIC_RELEASE); 104 | switch_to_active_task(); 105 | } 106 | 107 | void kernel_signal_cv(kernel_cv* m) 108 | { 109 | tas_release(&m->unavailable); 110 | switch_to_active_task(); 111 | } 112 | 113 | void kernel_wait_cv(kernel_mutex* locked_mutex, kernel_cv* m) 114 | { 115 | while(true) 116 | { 117 | if(tas_aquire(&m->unavailable) == 0) 118 | { 119 | kernel_unlock_mutex(locked_mutex); 120 | return; 121 | } 122 | run_background_tasks(); 123 | } 124 | } 125 | 126 | /*void wait_umtex(uint32_t* mutex) 127 | { 128 | kernel_lock_mutex(mutex); 129 | }*/ -------------------------------------------------------------------------------- /drivers/ps2mouse.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | enum mouse_type 10 | { 11 | MOUSE_STANDARD = 0, 12 | MOUSE_WHEEL = 3, 13 | MOUSE_5BUTTON = 4 14 | }; 15 | 16 | struct ps2_mouse 17 | { 18 | uint8_t buffer[4]; 19 | size_t buf_index = 0; 20 | uint8_t state = 0; 21 | }; 22 | 23 | ps2_mouse mouse; 24 | 25 | static void handle_mouse_packet(ps2_mouse& mouse, rt_device* device) 26 | { 27 | auto time = sysclock_get_ticks(); 28 | 29 | mouse.buf_index = 0; 30 | 31 | auto new_state = mouse.buffer[0]; 32 | 33 | int rel_x = (int)mouse.buffer[1] - (((int)new_state << 4) & 0x100); 34 | int rel_y = (int)mouse.buffer[2] - (((int)new_state << 3) & 0x100); 35 | 36 | if(rel_x != 0) 37 | { 38 | handle_input_event(input_event{0, 0, rel_x, AXIS_MOTION, time}); 39 | } 40 | 41 | if(rel_y != 0) 42 | { 43 | handle_input_event(input_event{0, 1, -rel_y, AXIS_MOTION, time}); 44 | } 45 | 46 | uint8_t modified = mouse.state ^ new_state; 47 | 48 | if(modified & (1 << 0)) 49 | { 50 | auto ev = new_state & (1 << 0) ? BUTTON_DOWN : BUTTON_UP; 51 | 52 | handle_input_event(input_event{0, 0, 0, ev, time}); 53 | } 54 | 55 | if(modified & (1 << 1)) 56 | { 57 | auto ev = new_state & (1 << 0) ? BUTTON_DOWN : BUTTON_UP; 58 | 59 | handle_input_event(input_event{0, 1, 0, ev, time}); 60 | } 61 | 62 | 63 | if(modified & (1 << 2)) 64 | { 65 | auto ev = new_state & (1 << 0) ? BUTTON_DOWN : BUTTON_UP; 66 | 67 | handle_input_event(input_event{0, 2, 0, ev, time}); 68 | } 69 | 70 | 71 | if(device->class_ID == MOUSE_WHEEL) 72 | { 73 | 74 | } 75 | else if(device->class_ID == MOUSE_5BUTTON) 76 | { 77 | //if(modified & (1 << 1)) 78 | // new_state& (1 << 1); 79 | // 80 | //if(modified & (1 << 2)) 81 | // new_state& (1 << 2); 82 | } 83 | 84 | mouse.state = new_state; 85 | } 86 | 87 | static void mouse_handler(rt_device* device, const uint8_t* data, size_t length) 88 | { 89 | for(size_t i = 0; i < length; i++) 90 | { 91 | uint8_t byte = data[i]; 92 | 93 | mouse.buffer[mouse.buf_index] = byte; 94 | 95 | if(device->class_ID == MOUSE_WHEEL || device->class_ID == MOUSE_5BUTTON) 96 | { 97 | if(mouse.buf_index == 3) 98 | { 99 | handle_mouse_packet(mouse, device); 100 | continue; 101 | } 102 | } 103 | else if(mouse.buf_index == 2) 104 | { 105 | handle_mouse_packet(mouse, device); 106 | continue; 107 | } 108 | mouse.buf_index++; 109 | } 110 | } 111 | 112 | void ps2_send_command(rt_device* device, uint8_t byte) 113 | { 114 | device->send_bytes(device, &byte, 1); 115 | } 116 | 117 | void ps2_read(rt_device* device) 118 | { 119 | uint8_t buf; 120 | device->read_bytes(device, &buf, 1); 121 | } 122 | 123 | extern "C" void ps2mouse_init() 124 | { 125 | rt_device* device = find_realtime_device(0); 126 | 127 | if(!device) 128 | return; 129 | 130 | device->on_new_data = mouse_handler; 131 | 132 | ps2_send_command(device, 0xF5); 133 | ps2_read(device); 134 | ps2_send_command(device, 0xF6); 135 | ps2_read(device); 136 | ps2_send_command(device, 0xF4); 137 | ps2_read(device); 138 | 139 | mouse.buf_index = 0; 140 | } 141 | -------------------------------------------------------------------------------- /boot/fatload.asm: -------------------------------------------------------------------------------- 1 | [bits 16] 2 | %assign root_size (32 * _root_entries) / _bytes_per_sector 3 | %assign fats_size (_number_of_FATs * _sectors_per_FAT) 4 | %assign root_location fats_size + _reserved_sectors 5 | %assign datasector root_location + root_size 6 | %assign cluster_size _sectors_per_cluster * _bytes_per_sector 7 | 8 | FAT_LOCATION equ 0x500 9 | ROOT equ FAT_LOCATION + _bytes_per_sector 10 | DIR_ENTRY_SIZE equ 0x0020 11 | 12 | ; es:bx = load address, si = file name 13 | ; trashes ax, dx, si, cx, di 14 | fat_load : 15 | ; read root directory into memory (0x0500) 16 | push bx ; save load address 17 | 18 | mov cx, root_size 19 | mov ax, root_location 20 | mov bx, ROOT 21 | call load_disk_ss 22 | 23 | pop bx ; restore load address 24 | ; browse root directory for filename 25 | mov ax, _root_entries ; load loop counter 26 | mov di, ROOT ; locate first root entry 27 | 28 | .LOOP: 29 | push es 30 | push ds 31 | pop es 32 | push si 33 | push di 34 | mov cx, 0x000B ; eleven character name 35 | repe cmpsb ; test for entry match 36 | pop di 37 | pop si 38 | pop es 39 | je LOAD_FAT 40 | add di, DIR_ENTRY_SIZE ; queue next directory entry 41 | dec ax 42 | jnz .LOOP 43 | FAILURE: 44 | jmp $ ; did not find kernel image 45 | 46 | LOAD_FAT: 47 | xor ax, ax 48 | ;mov [fat_sector], ax ;reset the fat sector to 0 49 | mov dx, WORD [di + 0x001A] ; get the first cluster from the directory entry 50 | 51 | LOAD_FILE: 52 | mov ax, dx ; cluster to read 53 | push ax ; save cluster on stack 54 | 55 | ; LBA = (cluster - 2) * _sectors_per_cluster + datasector 56 | ; convert cluster to LBA 57 | sub ax, 0x0002 ; zero base cluster number 58 | mov cx, _sectors_per_cluster ; convert byte to word 59 | mul cx 60 | add ax, datasector ; base data sector 61 | 62 | call disk_load ; load cluster to es:bx 63 | 64 | ; compute next cluster 65 | pop si ; restore cluster from stack 66 | mov ax, si ; cluster + cluster / 2 67 | shr ax, 0x0001 ; divide by two 68 | add ax, si 69 | 70 | push bx ; save load address 71 | 72 | ; reads a word from the fat at index ax into dx 73 | xor dx, dx 74 | div word [bp_bytes_per_sector] 75 | add ax, _reserved_sectors 76 | cmp ax, [fat_sector] 77 | push dx ; save the offset into the fat sector 78 | je .skip_fat_load 79 | 80 | ; read FAT into memory (0x0500) 81 | inc cx ;1 sector, we already know cx == 0 after disk_load 82 | mov [fat_sector], ax ;save the fat sector 83 | mov bx, FAT_LOCATION ;read the FAT to ss:0x0500 84 | call load_disk_ss ;load 85 | .skip_fat_load: 86 | pop bx ; restore the offset into the fat sector 87 | mov dx, WORD [bx + FAT_LOCATION] 88 | 89 | test si, 0x0001 90 | jz .EVEN_CLUSTER 91 | .ODD_CLUSTER: 92 | shr dx, 0x0004 ; take high twelve bits 93 | .EVEN_CLUSTER: 94 | and dx, 0x0FFF ; take low twelve bits 95 | 96 | .DONE: 97 | pop bx ; restore load address 98 | cmp dx, 0x0FF0 ; test for end of file 99 | jb LOAD_FILE 100 | 101 | DONE: 102 | ret ; file is loaded 103 | 104 | load_disk_ss: 105 | push es 106 | push ss 107 | pop es 108 | call disk_load ;load 109 | pop es 110 | ret 111 | 112 | fat_sector dw 0 -------------------------------------------------------------------------------- /drivers/cmos.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | static uint8_t century_register = 0; 8 | 9 | static int cmos_get_weekday(int month, int day, int year) //returns the day of the week using Sakamoto's Algorithm 10 | { 11 | static const int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; 12 | year -= month < 3; 13 | return (year + year / 4 - year / 100 + year / 400 + t[month - 1] + day) % 7; 14 | } 15 | 16 | clock_t cmos_get_date_time(struct tm* result) 17 | { 18 | while(cmos_get_update_flag()); 19 | 20 | clock_t sample_time = sysclock_get_ticks(); 21 | 22 | result->tm_sec = cmos_get_register(0x00); 23 | result->tm_min = cmos_get_register(0x02); 24 | result->tm_hour = cmos_get_register(0x04); 25 | result->tm_mday = cmos_get_register(0x07); 26 | result->tm_mon = cmos_get_register(0x08); 27 | result->tm_year = cmos_get_register(0x09); 28 | 29 | uint8_t century = 0; 30 | if(century_register != 0) 31 | { 32 | century = cmos_get_register(century_register); 33 | } 34 | 35 | int last_second; 36 | int last_minute; 37 | int last_hour; 38 | int last_day; 39 | int last_month; 40 | int last_year; 41 | int last_century; 42 | 43 | do 44 | { 45 | last_second = result->tm_sec; 46 | last_minute = result->tm_min; 47 | last_hour = result->tm_hour; 48 | last_day = result->tm_mday; 49 | last_month = result->tm_mon; 50 | last_year = result->tm_year; 51 | last_century = century; 52 | 53 | while(cmos_get_update_flag()); 54 | 55 | result->tm_sec = cmos_get_register(0x00); 56 | result->tm_min = cmos_get_register(0x02); 57 | result->tm_hour = cmos_get_register(0x04); 58 | result->tm_mday = cmos_get_register(0x07); 59 | result->tm_mon = cmos_get_register(0x08); 60 | result->tm_year = cmos_get_register(0x09); 61 | 62 | if(century_register != 0) 63 | { 64 | century = cmos_get_register(century_register); 65 | } 66 | } while((last_second != result->tm_sec) || 67 | (last_minute != result->tm_min) || 68 | (last_hour != result->tm_hour) || 69 | (last_day != result->tm_mday) || 70 | (last_month != result->tm_mon) || 71 | (last_year != result->tm_year) || 72 | (last_century != century)); 73 | 74 | uint8_t registerB = cmos_get_register(0x0B); 75 | 76 | if(!(registerB & 0x04)) //if we got values as BCD, then convert to binary 77 | { 78 | result->tm_sec = (result->tm_sec & 0x0F) + ((result->tm_sec / 16) * 10); 79 | result->tm_min = (result->tm_min & 0x0F) + ((result->tm_min / 16) * 10); 80 | result->tm_hour = ((result->tm_hour & 0x0F) + (((result->tm_hour & 0x70) / 16) * 10)) | (result->tm_hour & 0x80); 81 | result->tm_mday = (result->tm_mday & 0x0F) + ((result->tm_mday / 16) * 10); 82 | result->tm_mon = (result->tm_mon & 0x0F) + ((result->tm_mon / 16) * 10); 83 | result->tm_year = (result->tm_year & 0x0F) + ((result->tm_year / 16) * 10); 84 | 85 | if(century_register != 0) 86 | { 87 | century = (century & 0x0F) + ((century / 16) * 10); 88 | } 89 | } 90 | 91 | if(!(registerB & 0x02) && (result->tm_hour & 0x80)) 92 | { 93 | result->tm_hour = ((result->tm_hour & 0x7F) + 12) % 24; 94 | } 95 | 96 | if(century_register != 0) 97 | { 98 | result->tm_year += century * 100; 99 | } 100 | else 101 | { 102 | result->tm_year += (2014 / 100) * 100; 103 | 104 | if(result->tm_year < 2014) 105 | { 106 | result->tm_year += 100; 107 | } 108 | } 109 | 110 | result->tm_wday = cmos_get_weekday(result->tm_mon, result->tm_mday, result->tm_year); 111 | 112 | result->tm_mon -= 1; 113 | result->tm_year -= 1900; 114 | 115 | result->tm_isdst = 0; 116 | 117 | return sample_time; 118 | } -------------------------------------------------------------------------------- /cpplib/include/iterator: -------------------------------------------------------------------------------- 1 | #ifndef STD_ITERATOR_TRAITS_H 2 | #define STD_ITERATOR_TRAITS_H 3 | namespace std 4 | { 5 | #include 6 | 7 | template 8 | struct iterator_traits; 9 | 10 | struct input_iterator_tag 11 | { 12 | }; 13 | struct output_iterator_tag 14 | { 15 | }; 16 | struct forward_iterator_tag : public input_iterator_tag 17 | { 18 | }; 19 | struct bidirectional_iterator_tag : public forward_iterator_tag 20 | { 21 | }; 22 | struct random_access_iterator_tag : public bidirectional_iterator_tag 23 | { 24 | }; 25 | struct contiguous_iterator_tag : public random_access_iterator_tag 26 | { 27 | }; 28 | 29 | template 30 | constexpr typename iterator_traits::difference_type distance(It first, 31 | It last) 32 | { 33 | using category = typename iterator_traits::iterator_category; 34 | static_assert(is_base_of_v); 35 | 36 | if constexpr(is_base_of_v) 37 | { 38 | return last - first; 39 | } 40 | else 41 | { 42 | typename iterator_traits::difference_type result = 0; 43 | while(first != last) 44 | { 45 | ++first; 46 | ++result; 47 | } 48 | return result; 49 | } 50 | } 51 | 52 | template 53 | constexpr void advance(It& it, Distance n) 54 | { 55 | using category = typename iterator_traits::iterator_category; 56 | static_assert(is_base_of_v); 57 | 58 | auto dist = typename iterator_traits::difference_type(n); 59 | if constexpr(is_base_of_v) 60 | { 61 | it += dist; 62 | } 63 | else 64 | { 65 | while(dist > 0) 66 | { 67 | --dist; 68 | ++it; 69 | } 70 | if constexpr(is_base_of_v) 71 | { 72 | while(dist < 0) 73 | { 74 | ++dist; 75 | --it; 76 | } 77 | } 78 | } 79 | } 80 | 81 | template 82 | constexpr InputIt next(InputIt it, 83 | typename iterator_traits::difference_type n = 1) 84 | { 85 | advance(it, n); 86 | return it; 87 | } 88 | 89 | template 90 | struct iterator_traits 91 | { 92 | using difference_type = ptrdiff_t; 93 | using value_type = remove_cv_t; 94 | using pointer = T*; 95 | using reference = T&; 96 | using iterator_category = random_access_iterator_tag; 97 | }; 98 | 99 | template 100 | class back_insert_iterator 101 | { 102 | public: 103 | using iterator_category = output_iterator_tag; 104 | using value_type = void; 105 | using difference_type = ptrdiff_t; 106 | using pointer = void; 107 | using reference = void; 108 | using container_type = Container; 109 | 110 | constexpr explicit back_insert_iterator(Container& x) : container(&x) 111 | { 112 | } 113 | 114 | constexpr back_insert_iterator& 115 | operator=(const typename Container::value_type& value) 116 | { 117 | container->push_back(value); 118 | return *this; 119 | } 120 | 121 | constexpr back_insert_iterator& 122 | operator=(typename Container::value_type&& value) 123 | { 124 | container->push_back(std::move(value)); 125 | return *this; 126 | } 127 | 128 | constexpr back_insert_iterator& operator++() 129 | { 130 | return *this; 131 | } 132 | constexpr back_insert_iterator& operator++(int) 133 | { 134 | return *this; 135 | } 136 | constexpr back_insert_iterator& operator*() 137 | { 138 | return *this; 139 | } 140 | protected: 141 | Container* container; 142 | }; 143 | 144 | template 145 | constexpr back_insert_iterator back_inserter(Container& c) 146 | { 147 | return back_insert_iterator(c); 148 | } 149 | 150 | } 151 | #endif 152 | -------------------------------------------------------------------------------- /kernel/task.asm: -------------------------------------------------------------------------------- 1 | [bits 32] 2 | 3 | section .data 4 | 5 | struc GDT_SEG 6 | .limit_lo: resw 1 7 | .base_lo: resw 1 8 | .base_mid: resb 1 9 | .access: resb 1 10 | .granularity: resb 1 11 | .base_hi: resb 1 12 | endstruc 13 | 14 | struc GDT 15 | .null: resb GDT_SEG_size 16 | .code: resb GDT_SEG_size 17 | .data: resb GDT_SEG_size 18 | .user_code: resb GDT_SEG_size 19 | .user_data: resb GDT_SEG_size 20 | .tls_data: resb GDT_SEG_size 21 | .cpu_data: resb GDT_SEG_size 22 | .tss_data: resb GDT_SEG_size 23 | endstruc 24 | 25 | struc TSS 26 | .link: resw 1 27 | .reserved0: resw 1 28 | .esp0: resd 1 29 | .ss: resw 1 30 | .reserved1: resw 1 31 | .other: resd 23 32 | endstruc 33 | 34 | struc CPU_state 35 | .self_ptr: resd 1 36 | 37 | .tss: resb TSS_size 38 | .gdt: resb GDT_size 39 | 40 | .tcb_ptr: resd 1 41 | endstruc 42 | 43 | struc TCB 44 | .esp: resd 1 45 | .esp0: resd 1 46 | .cr3: resd 1 47 | .tls_gdt_hi: resd 1 48 | .tls_base_lo: resw 1 49 | .padding: resw 1 50 | 51 | .running: resb 1 52 | endstruc 53 | 54 | section .text 55 | 56 | global run_user_code 57 | run_user_code: 58 | mov ebx, [esp + 4] ;code address 59 | mov ecx, [esp + 8] ;stack address 60 | 61 | mov ax, GDT.user_data 62 | mov ds, ax 63 | mov es, ax 64 | ;mov fs, ax 65 | 66 | ;FS can be left as is (CPU seg) 67 | ;GS can be left as is (TLS seg) 68 | 69 | ;SS & CS set up here for iret to hande: 70 | 71 | push GDT.user_data | 3 ;user data segment with bottom 2 bits set for ring 3 72 | push ecx ;push the new user stack 73 | pushf ;push flags 74 | push GDT.user_code | 3 ;user code segment with bottom 2 bits set for ring 3 75 | push ebx ;address of the user function 76 | iret 77 | 78 | [extern current_task_TCB] 79 | 80 | global switch_task_no_return 81 | switch_task_no_return: 82 | cli 83 | mov esi, [esp + 4] 84 | jmp load_new_task 85 | 86 | global switch_task 87 | switch_task: 88 | pushfd 89 | cli 90 | push ebx 91 | push esi 92 | push edi 93 | push ebp 94 | 95 | mov edi, [fs:CPU_state.tcb_ptr] ; edi = address of the previous task's "thread control block" 96 | mov eax, cr3 97 | mov [edi + TCB.esp], esp ; Save ESP for previous task's kernel stack in the thread's TCB 98 | mov [edi + TCB.cr3], eax 99 | 100 | ;Load next task's state 101 | mov esi, [esp + (5+1)*4] ; esi = address of the next task's "thread control block" (parameter passed on stack) 102 | 103 | ; atomically mark the previous task as not running 104 | ; don't touch the stack after this 105 | xor al, al 106 | xchg [edi + TCB.running], al 107 | 108 | load_new_task: 109 | mov [fs:CPU_state.tcb_ptr], esi ; Current task's TCB is the next task TCB 110 | 111 | ;copy the required data into the gdt 112 | mov ax, [esi + TCB.tls_base_lo] 113 | mov [fs:(CPU_state.gdt + GDT.tls_data + GDT_SEG.base_lo)], ax 114 | mov eax, [esi + TCB.tls_gdt_hi] 115 | mov [fs:(CPU_state.gdt + GDT.tls_data + GDT_SEG.base_mid)], eax 116 | 117 | ;reload gs 118 | mov ax, GDT.tls_data | 3 119 | mov gs, ax 120 | 121 | mov esp, [esi + TCB.esp] ; Load ESP for next task's kernel stack from the thread's TCB 122 | mov eax, [esi + TCB.cr3] ; eax = address of page directory for next task 123 | mov ebx, [esi + TCB.esp0] ; ebx = address for the top of the next task's kernel stack 124 | 125 | mov [fs:(CPU_state.tss + TSS.esp0)], ebx ; Adjust the ESP0 field in the TSS 126 | 127 | ; check if we need to change page tables 128 | mov ecx, cr3 129 | cmp eax, ecx 130 | je .skip_cr3 131 | mov cr3, eax 132 | .skip_cr3: 133 | pop ebp 134 | pop edi 135 | pop esi 136 | pop ebx 137 | popfd 138 | ret -------------------------------------------------------------------------------- /kernel/util/hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_H 2 | #define HASH_H 3 | #ifdef __cplusplus 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | template 15 | class hash_map 16 | { 17 | public: 18 | constexpr hash_map(size_t num_buckets = 16) noexcept 19 | : buckets(num_buckets, nullptr) 20 | { 21 | assert(std::has_single_bit(num_buckets)); 22 | } 23 | 24 | ~hash_map() 25 | { 26 | for(size_t i = 0; i < buckets.size(); i++) 27 | { 28 | hash_node* entry = buckets[i]; 29 | 30 | while(entry != nullptr) 31 | { 32 | hash_node* prev = entry; 33 | entry = entry->next; 34 | delete prev; 35 | } 36 | 37 | buckets[i] = nullptr; 38 | } 39 | } 40 | 41 | template 42 | D* lookup(const _Ky& key) 43 | { 44 | const size_t i = hash(key) & (buckets.size() - 1); 45 | hash_node* entry = buckets[i]; 46 | 47 | while(entry != nullptr) 48 | { 49 | if(key == entry->key) 50 | { 51 | return &entry->data; 52 | } 53 | 54 | entry = entry->next; 55 | } 56 | 57 | return nullptr; 58 | } 59 | 60 | template 61 | bool lookup(const _Ky& key, D* value) 62 | requires(std::is_copy_assignable_v) 63 | { 64 | if(auto data = lookup(key); !!data) 65 | { 66 | *value = *data; 67 | return true; 68 | } 69 | 70 | return false; 71 | } 72 | 73 | template 74 | bool contains(const _Ky& key) 75 | { 76 | return !!lookup(key); 77 | } 78 | 79 | template 80 | D* insert(const _Ky& key, const D& value) 81 | { 82 | return emplace(key, value); 83 | } 84 | 85 | template 86 | D* emplace(const _Ky& key, Args&&... args) 87 | { 88 | size_t i = hash(key) & (buckets.size() - 1); 89 | hash_node* prev = nullptr; 90 | hash_node* entry = buckets[i]; 91 | 92 | while(entry != nullptr && entry->key != key) 93 | { 94 | prev = entry; 95 | entry = entry->next; 96 | } 97 | 98 | if(entry == nullptr) 99 | { 100 | entry = new hash_node{K(key), {std::forward(args)...}}; 101 | 102 | if(prev == nullptr) 103 | { 104 | buckets[i] = entry; 105 | } 106 | else 107 | { 108 | prev->next = entry; 109 | } 110 | return &entry->data; 111 | } 112 | 113 | return nullptr; 114 | } 115 | 116 | template 117 | void remove(const _Ky& key) 118 | { 119 | size_t i = hash(key) & (buckets.size() - 1); 120 | hash_node* prev = nullptr; 121 | hash_node* entry = buckets[i]; 122 | 123 | while(entry != nullptr && entry->key != key) 124 | { 125 | prev = entry; 126 | entry = entry->next; 127 | } 128 | 129 | if(entry == nullptr) 130 | { 131 | return; 132 | } 133 | else 134 | { 135 | if(prev == nullptr) 136 | { 137 | buckets[i] = entry->next; 138 | } 139 | else 140 | { 141 | prev->next = entry->next; 142 | } 143 | delete entry; 144 | } 145 | } 146 | 147 | private: 148 | constexpr static uint32_t hash(uint32_t x) 149 | { 150 | x = ((x >> 16) ^ x) * 0x45d9f3b; 151 | x = ((x >> 16) ^ x) * 0x45d9f3b; 152 | x = (x >> 16) ^ x; 153 | return x; 154 | } 155 | 156 | constexpr static uint32_t hash(const std::string_view name) 157 | { 158 | uint32_t h = 0; 159 | for(size_t i = 0; i < name.size(); i++) 160 | { 161 | h = (h << 4) + *(uint8_t*)&name[i]; 162 | const uint32_t g = h & 0xf0000000; 163 | if(g) 164 | { 165 | h ^= g >> 24; 166 | } 167 | h &= ~g; 168 | } 169 | return h; 170 | } 171 | 172 | struct hash_node 173 | { 174 | K key; 175 | D data; 176 | hash_node* next = nullptr; 177 | }; 178 | 179 | std::vector buckets; 180 | }; 181 | 182 | #endif 183 | #endif -------------------------------------------------------------------------------- /api/crt0.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | extern void exit(int status); 7 | extern int main(int argc, char** argv); 8 | extern void _init(); 9 | extern void _fini(); 10 | 11 | typedef void func_t(void); 12 | extern func_t *__init_array_start[], *__init_array_end[]; 13 | extern func_t *__fini_array_start[], *__fini_array_end[]; 14 | 15 | static void handle_init_array(void) 16 | { 17 | for(func_t** func = __init_array_start; func != __init_array_end; func++) 18 | (*func)(); 19 | } 20 | 21 | void handle_fini_array(void) 22 | { 23 | for(func_t** func = __fini_array_start; func != __fini_array_end; func++) 24 | (*func)(); 25 | } 26 | 27 | static const char* _find(const char* first, const char* last, char value) 28 | { 29 | for(; first != last; ++first) 30 | { 31 | if(*first == value) 32 | { 33 | return first; 34 | } 35 | } 36 | return last; 37 | } 38 | 39 | static int count_tokens(const char* input, size_t input_size, char delim) 40 | { 41 | int num_tokens = 0; 42 | 43 | const char* first = input; 44 | const char* last = input + input_size; 45 | while(first < last) 46 | { 47 | const char* second = (const char*)_find(first, last, delim); 48 | 49 | if(first != second) num_tokens++; 50 | 51 | first = second + 1; 52 | } 53 | return num_tokens; 54 | } 55 | 56 | static void tokenize(const char** buf, const char* input, size_t input_size, 57 | char delim) 58 | { 59 | size_t index = 0; 60 | 61 | const char* first = input; 62 | const char* last = input + input_size; 63 | while(first < last) 64 | { 65 | const char* second = (const char*)_find(first, last, delim); 66 | if(first != second) 67 | { 68 | buf[index++] = first; 69 | } 70 | first = second + 1; 71 | } 72 | } 73 | 74 | void _start(uintptr_t args) 75 | { 76 | uintptr_t args_begin = (uintptr_t)&args + sizeof(uintptr_t); 77 | size_t args_size; 78 | memcpy(&args_size, (void*)args_begin, sizeof(size_t)); 79 | 80 | char* args_ptr = (char*)(args_begin + sizeof(size_t)); 81 | 82 | int argc = count_tokens(args_ptr, args_size, '\0'); 83 | 84 | char** argv = (char**)malloc(sizeof(char**) * (size_t)argc); 85 | 86 | tokenize(argv, args_ptr, args_size, '\0'); 87 | 88 | _init(); 89 | 90 | handle_init_array(); 91 | 92 | int r = main(argc, argv); 93 | 94 | handle_fini_array(); 95 | 96 | _fini(); 97 | 98 | exit(r); 99 | } 100 | 101 | void __cxa_pure_virtual() { 102 | // Do Nothing 103 | } 104 | 105 | #define ATEXIT_FUNC_MAX 128 106 | 107 | typedef unsigned uarch_t; 108 | 109 | struct atexitFuncEntry_t { 110 | void (*destructorFunc) (void*); 111 | void* objPtr; 112 | void* dsoHandle; 113 | 114 | }; 115 | 116 | struct atexitFuncEntry_t __atexitFuncs[ATEXIT_FUNC_MAX]; 117 | uarch_t __atexitFuncCount = 0; 118 | 119 | void* __dso_handle = 0; 120 | 121 | int __cxa_atexit(void (*f)(void*), void* objptr, void* dso) { 122 | if(__atexitFuncCount >= ATEXIT_FUNC_MAX) { 123 | return -1; 124 | } 125 | __atexitFuncs[__atexitFuncCount].destructorFunc = f; 126 | __atexitFuncs[__atexitFuncCount].objPtr = objptr; 127 | __atexitFuncs[__atexitFuncCount].dsoHandle = dso; 128 | __atexitFuncCount++; 129 | return 0; 130 | } 131 | 132 | void __cxa_finalize(void* f) { 133 | unsigned int i = __atexitFuncCount; 134 | if(!f) { 135 | while(i--) { 136 | if(__atexitFuncs[i].destructorFunc) { 137 | (*__atexitFuncs[i].destructorFunc)(__atexitFuncs[i].objPtr); 138 | } 139 | } 140 | return; 141 | } 142 | 143 | for(; i >= 0; i--) { 144 | if(__atexitFuncs[i].destructorFunc == f) { 145 | (*__atexitFuncs[i].destructorFunc)(__atexitFuncs[i].objPtr); 146 | __atexitFuncs[i].destructorFunc = 0; 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /boot/boot_sect.asm: -------------------------------------------------------------------------------- 1 | [bits 16] 2 | [org 0x7c00] 3 | start: jmp begin 4 | nop 5 | 6 | %assign _bytes_per_sector 512 7 | %assign _sectors_per_cluster 1 8 | %assign _reserved_sectors 1 9 | %assign _number_of_FATs 2 10 | %assign _root_entries 224 11 | %assign _total_sectors 2880 12 | %assign _media 0xf8 13 | %assign _sectors_per_FAT 9 14 | %assign _sectors_per_track 18 15 | %assign _heads_per_cylinder 2 16 | %assign _hidden_sectors 0 17 | %assign _total_sectors_big 0 18 | %assign _drive_number 0 19 | %assign _unused 0 20 | %assign _ext_boot_signature 0x29 21 | %assign _serial_number 0xa0a1a2a3 22 | 23 | ; BIOS Parameter Block 24 | bp_OEM: db "JSD OS " 25 | bp_bytes_per_sector: dw _bytes_per_sector 26 | bp_sectors_per_cluster: db _sectors_per_cluster 27 | bp_reserved_sectors: dw _reserved_sectors 28 | bp_number_of_FATs: db _number_of_FATs 29 | bp_root_entries: dw _root_entries 30 | bp_total_sectors: dw _total_sectors 31 | bp_media: db _media 32 | bp_sectors_per_FAT: dw _sectors_per_FAT 33 | bp_sectors_per_track: dw _sectors_per_track 34 | bp_heads_per_cylinder: dw _heads_per_cylinder 35 | bp_hidden_sectors: dd _hidden_sectors 36 | bp_total_sectors_big: dd _total_sectors_big 37 | bs_drive_number: db _drive_number 38 | bs_unused: db _unused 39 | bs_ext_boot_signature: db _ext_boot_signature 40 | bs_serial_number: dd _serial_number 41 | bs_volume_label: db "FLOPPY " 42 | bs_file_system: db "FAT12 " 43 | 44 | KERNEL_OFFSET equ 0x9000 ; This is the memory address where our kernel goes 45 | 46 | MULTIBOOT_OFFSET equ 0x7000 47 | 48 | RAMDISK_DATA equ MULTIBOOT_OFFSET + multiboot_info_size 49 | 50 | begin: 51 | 52 | xor ax, ax 53 | mov ds, ax 54 | mov es, ax 55 | mov ss, ax 56 | mov sp, 0x6000 57 | mov bp, sp 58 | 59 | mov [MULTIBOOT_OFFSET + multiboot_info.bootDevice], dl ; Save the index of the boot drive 60 | 61 | call getmem 62 | 63 | mov bx, KERNEL_OFFSET 64 | ;mov si, ramdisk_begin 65 | ;call store_as_long_address 66 | 67 | mov si, kernel_file_name 68 | call fat_load 69 | 70 | mov si, RAMDISK_DATA + multiboot_module.begin 71 | call store_as_long_address 72 | 73 | mov si, raminit_file_name 74 | call fat_load 75 | 76 | mov si, RAMDISK_DATA + multiboot_module.end 77 | call store_as_long_address 78 | 79 | switchtopm: 80 | cli 81 | lgdt [gdt_descriptor] ; Load our global descriptor table , which defines 82 | mov eax, cr0 ; To make the switch to protected mode , we set 83 | or eax, 0x01 ; the first bit of CR0 , a control register 84 | mov cr0, eax 85 | jmp CODE_SEG : init_pm ; Make a far jump ( i.e. to a new segment ) to our 32 - bit 86 | 87 | [bits 32] 88 | ; Initialise registers and the stack once in PM. 89 | init_pm : 90 | mov ax, DATA_SEG ; Now in PM , our old segments are meaningless , 91 | mov ds, ax ; so we point our segment registers to the 92 | mov ss, ax ; data selector we defined in our GDT 93 | mov es, ax 94 | mov fs, ax 95 | mov gs, ax 96 | mov ebp, 0x90000 ; Update our stack position so it is right 97 | mov esp, ebp ; at the top of the free space. 98 | 99 | ; In protected mode now 100 | BEGIN_PM : 101 | 102 | mov ebx, MULTIBOOT_OFFSET 103 | xor eax, eax 104 | inc eax 105 | mov [ebx + multiboot_info.mods_count], eax 106 | mov eax, RAMDISK_DATA 107 | mov [ebx + multiboot_info.mods_addr], eax 108 | 109 | mov eax, 0x2badb002 ;multiboot magic 110 | 111 | call KERNEL_OFFSET ; Jumping into C and Kernel land 112 | 113 | %include "disk.asm" 114 | %include "memmap.asm" 115 | %include "gdt.asm" 116 | %include "multiboot.asm" 117 | %include "fatload.asm" 118 | 119 | store_as_long_address: 120 | mov ax, es 121 | ;mov cx, ax 122 | ;shl cx, 4 123 | ;add bx, cx 124 | mov word [si], bx 125 | shr ax, 0x0c 126 | mov word [si + 0x02], ax 127 | ret 128 | 129 | kernel_file_name db "KERNAL SYS" 130 | raminit_file_name db "INIT RFS" 131 | 132 | 133 | ; Bootsector padding 134 | times 510 -( $ - $$ ) db 0 135 | 136 | ; magic number 137 | dw 0xaa55 -------------------------------------------------------------------------------- /kernel/kernel.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | extern void _IMAGE_END_; 23 | 24 | typedef void (*func_ptr)(void); 25 | extern func_ptr __init_array_start[], __init_array_end[]; 26 | static void handle_init_array(void) 27 | { 28 | for(func_ptr* func = __init_array_start; func != __init_array_end; func++) 29 | (*func)(); 30 | } 31 | 32 | extern void memmanager_print_free_map(); 33 | 34 | extern void _RECLAIMABLE_CODE_BEGIN_, _RECLAIMABLE_CODE_END_; 35 | extern void _RECLAIMABLE_DATA_BEGIN_, _RECLAIMABLE_DATA_END_; 36 | extern void _RECLAIMABLE_BSS_BEGIN_, _RECLAIMABLE_BSS_END_; 37 | 38 | RECLAIMABLE void init_kernel_state() __attribute__((noinline)) 39 | { 40 | parse_boot_info(); 41 | 42 | setup_boot_cpu(); 43 | 44 | interrupts_init(); 45 | 46 | reserve_boot_mem(); 47 | 48 | physical_memory_init(); 49 | 50 | memmanager_init(); 51 | 52 | //call global constructors 53 | handle_init_array(); 54 | 55 | setup_first_task(); //we are now running as a kernel level task 56 | } 57 | extern void print_free_map(); 58 | 59 | void kernel_main() 60 | { 61 | init_kernel_state(); 62 | 63 | //jettison the boostrap code 64 | physical_memory_free(memmanager_get_physical(&_RECLAIMABLE_CODE_BEGIN_), 65 | &_RECLAIMABLE_CODE_END_ - &_RECLAIMABLE_CODE_BEGIN_); 66 | physical_memory_free(memmanager_get_physical(&_RECLAIMABLE_DATA_BEGIN_), 67 | &_RECLAIMABLE_DATA_END_ - &_RECLAIMABLE_DATA_BEGIN_); 68 | physical_memory_free(memmanager_get_physical(&_RECLAIMABLE_BSS_BEGIN_), 69 | &_RECLAIMABLE_BSS_END_ - &_RECLAIMABLE_BSS_BEGIN_); 70 | 71 | basic_text_init(); 72 | 73 | printf( "Found Kernel: %X - %X\n", 74 | boot_information.kernel_location, 75 | boot_information.kernel_location + boot_information.kernel_size); 76 | 77 | printf( "Found Ram Disk: %X - %X\n", 78 | boot_information.ramdisk_location, 79 | boot_information.ramdisk_location + boot_information.ramdisk_size); 80 | 81 | sysclock_init(); 82 | 83 | setup_syscalls(); 84 | 85 | ramdisk_init(); 86 | 87 | rdfs_init(); 88 | 89 | load_drivers(); 90 | 91 | for(;;) 92 | { 93 | __asm__ volatile("hlt"); 94 | } 95 | } 96 | 97 | void __cxa_pure_virtual() { 98 | // Do Nothing 99 | } 100 | 101 | #define ATEXIT_FUNC_MAX 128 102 | 103 | typedef unsigned uarch_t; 104 | 105 | struct atexitFuncEntry_t { 106 | void (*destructorFunc) (void*); 107 | void* objPtr; 108 | void* dsoHandle; 109 | 110 | }; 111 | 112 | struct atexitFuncEntry_t __atexitFuncs[ATEXIT_FUNC_MAX]; 113 | uarch_t __atexitFuncCount = 0; 114 | 115 | void* __dso_handle = 0; 116 | 117 | int __cxa_atexit(void (*f)(void*), void* objptr, void* dso) { 118 | if(__atexitFuncCount >= ATEXIT_FUNC_MAX) { 119 | return -1; 120 | } 121 | __atexitFuncs[__atexitFuncCount].destructorFunc = f; 122 | __atexitFuncs[__atexitFuncCount].objPtr = objptr; 123 | __atexitFuncs[__atexitFuncCount].dsoHandle = dso; 124 | __atexitFuncCount++; 125 | return 0; 126 | } 127 | 128 | void __cxa_finalize(void* f) { 129 | size_t i = __atexitFuncCount; 130 | if(!f) 131 | { 132 | while(i--) 133 | { 134 | if(__atexitFuncs[i].destructorFunc) 135 | { 136 | (*__atexitFuncs[i].destructorFunc)(__atexitFuncs[i].objPtr); 137 | } 138 | } 139 | return; 140 | } 141 | 142 | while(i--) 143 | { 144 | if(__atexitFuncs[i].destructorFunc == f) 145 | { 146 | (*__atexitFuncs[i].destructorFunc)(__atexitFuncs[i].objPtr); 147 | __atexitFuncs[i].destructorFunc = 0; 148 | } 149 | } 150 | } -------------------------------------------------------------------------------- /kernel/filesystem/fs_driver.h: -------------------------------------------------------------------------------- 1 | #ifndef FS_DRIVER_H 2 | #define FS_DRIVER_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | struct filesystem_driver; 10 | typedef struct filesystem_driver filesystem_driver; 11 | 12 | struct disk_driver; 13 | typedef struct disk_driver disk_driver; 14 | 15 | struct directory_stream; 16 | typedef struct directory_stream directory_stream; 17 | 18 | struct filesystem_virtual_drive; 19 | typedef struct filesystem_virtual_drive filesystem_virtual_drive; 20 | 21 | struct filesystem_drive; 22 | typedef struct filesystem_drive filesystem_drive; 23 | 24 | typedef int (*partition_func)(filesystem_drive*, filesystem_virtual_drive*, size_t block_size); 25 | 26 | void filesystem_write_to_disk(const filesystem_drive* d, size_t block, size_t offset, const uint8_t* buf, size_t num_bytes); 27 | void filesystem_read_from_disk(const filesystem_drive* d, size_t block, size_t offset, uint8_t* buf, size_t num_bytes); 28 | 29 | struct filesystem_driver 30 | { 31 | mount_status (*mount_disk)(filesystem_virtual_drive* d); 32 | fs_index (*read_chunks)(uint8_t* dest, fs_index location, 33 | file_size_t offset, size_t num_bytes, 34 | const file_data_block* file, 35 | const filesystem_virtual_drive* fd); 36 | fs_index (*write_chunks)(const uint8_t* dest, fs_index location, 37 | file_size_t offset, size_t num_bytes, 38 | const file_data_block* file, 39 | const filesystem_virtual_drive* fd); 40 | file_size_t(*allocate_chunks)(fs_index location, size_t num_bytes, const file_data_block* file, const filesystem_virtual_drive* d); 41 | void (*read_dir)(directory_stream* dest, const file_data_block* dir, const filesystem_virtual_drive* fd); 42 | void (*flush_file)(const file_data_block* file, const filesystem_virtual_drive* fd); 43 | void (*create_file)(const char* name, size_t name_len, uint32_t flags, directory_stream* dir, const filesystem_virtual_drive* fd); 44 | int (*delete_file)(const file_data_block* file, const filesystem_virtual_drive* fd); 45 | }; 46 | 47 | struct disk_driver 48 | { 49 | void (*read_blocks)(void* driver_data, size_t block_number, uint8_t* buf, size_t num_blocks); 50 | void (*write_blocks)(void* driver_data, size_t block_number, const uint8_t* buf, size_t num_blocks); 51 | uint8_t* (*allocate_buffer)(size_t size); 52 | int (*free_buffer)(uint8_t* buffer, size_t size); 53 | }; 54 | 55 | void filesystem_add_driver(const filesystem_driver* fs_drv); 56 | filesystem_drive* filesystem_add_drive(const disk_driver* disk_drv, void* driver_data, size_t block_size, size_t num_blocks); 57 | void filesystem_add_virtual_drive(filesystem_drive* disk, fs_index begin, size_t size); 58 | void filesystem_add_partitioner(partition_func p); 59 | 60 | file_stream* filesystem_create_stream(const file_data_block* f); 61 | 62 | #ifdef __cplusplus 63 | } 64 | 65 | #include 66 | #include 67 | 68 | //information about a directory on disk 69 | struct directory_stream 70 | { 71 | intrusive_ptr full_path; 72 | file_data_block data; 73 | std::vector file_list; 74 | }; 75 | 76 | //represents a partition on a drive 77 | struct filesystem_virtual_drive 78 | { 79 | filesystem_virtual_drive(filesystem_drive* disk, fs_index begin, size_t size); 80 | 81 | filesystem_drive* disk; 82 | void* fs_impl_data; 83 | const filesystem_driver* fs_driver; 84 | size_t id; 85 | fs_index first_block; 86 | size_t num_blocks; 87 | size_t block_size; 88 | 89 | file_handle root_dir; 90 | 91 | std::string root_name; 92 | 93 | bool mounted; 94 | bool read_only; 95 | }; 96 | 97 | inline void filesystem_write(const filesystem_virtual_drive* d, size_t block, size_t offset, const uint8_t* buf, size_t num_bytes) 98 | { 99 | filesystem_write_to_disk(d->disk, block + d->first_block, offset, buf, num_bytes); 100 | } 101 | inline void filesystem_read(const filesystem_virtual_drive* d, size_t block, size_t offset, uint8_t* buf, size_t num_bytes) 102 | { 103 | filesystem_read_from_disk(d->disk, block + d->first_block, offset, buf, num_bytes); 104 | } 105 | 106 | 107 | #endif 108 | 109 | #endif -------------------------------------------------------------------------------- /apps/init.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | struct dir_deleter 8 | { 9 | void operator()(directory_stream* b) 10 | { 11 | close_dir(b); 12 | } 13 | }; 14 | 15 | using directory_ptr = std::unique_ptr; 16 | 17 | struct file_deleter 18 | { 19 | void operator()(file_stream* b) 20 | { 21 | close(b); 22 | } 23 | }; 24 | 25 | using file_ptr = std::unique_ptr; 26 | 27 | struct file_handle_deleter 28 | { 29 | void operator()(const file_handle* f) 30 | { 31 | dispose_file_handle(f); 32 | } 33 | }; 34 | 35 | using file_h = std::unique_ptr; 36 | 37 | using namespace std::literals; 38 | 39 | static inline void print(char c) 40 | { 41 | diagnostic_message(&c, 1); 42 | } 43 | 44 | static inline void print(std::string_view text) 45 | { 46 | diagnostic_message(text.data(), text.size()); 47 | } 48 | 49 | template 50 | static inline void print_strings(Args&&... args) 51 | { 52 | (print(std::forward(args)), ...); 53 | } 54 | 55 | static void process_init_file(directory_stream* cwd, file_stream* f); 56 | 57 | static void execute_line(std::string_view line, directory_stream* cwd) 58 | { 59 | auto space = line.find_first_of(' '); 60 | auto token = line.substr(0, space); 61 | 62 | if(line.size() >= 2 && line[0] == '/' && line[1] == '/') 63 | { 64 | } 65 | else if(token == "load_driver"sv) 66 | { 67 | auto filename = line.substr(space + 1); 68 | 69 | print_strings("Loading driver "sv, filename, '\n'); 70 | 71 | file_h f{find_path(cwd, filename.data(), filename.size(), 0, 0)}; 72 | if(!f) 73 | { 74 | print_strings("Can't find driver ", filename, '\n'); 75 | return; 76 | } 77 | 78 | if(load_driver(cwd, f.get()) != 0) 79 | { 80 | print_strings("Error loading driver ", filename, '\n'); 81 | } 82 | } 83 | else if(token == "load_file"sv) 84 | { 85 | auto filename = line.substr(space + 1); 86 | 87 | //TODO: fix this stupid hack! 88 | size_t num_drives = 10; 89 | for(size_t drive = 0; drive < num_drives; drive++) 90 | { 91 | file_h root{get_root_directory(drive)}; 92 | 93 | if(!root) continue; 94 | 95 | directory_ptr dir{open_dir_handle(root.get(), 0)}; 96 | 97 | if(!dir) continue; 98 | 99 | if(file_ptr stream{ 100 | open(dir.get(), filename.data(), filename.size(), 0)}; 101 | !!stream) 102 | { 103 | print_strings("Processing file ", filename, '\n'); 104 | 105 | process_init_file(dir.get(), stream.get()); 106 | return; 107 | } 108 | } 109 | print_strings("Can't find ", filename, '\n'); 110 | } 111 | else if(token == "execute"sv) 112 | { 113 | auto filename = line.substr(space + 1); 114 | auto f = find_path(cwd, filename.data(), filename.size(), 0, 0); 115 | 116 | if(!f) 117 | { 118 | print_strings("Can't find ", filename, '\n'); 119 | } 120 | else 121 | { 122 | print_strings("Executing ", filename, '\n'); 123 | 124 | spawn_process(&(*f), nullptr, 0, WAIT_FOR_PROCESS); 125 | } 126 | } 127 | } 128 | 129 | static void process_init_file(directory_stream* cwd, file_stream* f) 130 | { 131 | assert(cwd); 132 | 133 | file_size_t offset = 0; 134 | 135 | std::string buffer; 136 | bool eof = false; 137 | while(!eof) 138 | { 139 | char c; 140 | if(read(offset, &c, sizeof(char), f) != sizeof(char)) 141 | { 142 | eof = true; 143 | c = '\n'; 144 | } 145 | 146 | offset += sizeof(char); 147 | 148 | switch(c) 149 | { 150 | case '\r': 151 | continue; 152 | case '\n': 153 | execute_line(buffer, cwd); 154 | buffer.clear(); 155 | continue; 156 | default: 157 | buffer += c; 158 | } 159 | } 160 | } 161 | 162 | static constexpr std::string_view init_path = "init.sys"; 163 | 164 | int main(int argc, char** argv) 165 | { 166 | print_strings("Loading drivers\n"sv); 167 | 168 | directory_ptr cwd{open_dir_handle(get_root_directory(0), 0)}; 169 | 170 | if(!cwd) 171 | { 172 | print_strings("Corrupted boot drive!\n"); 173 | while(true); 174 | } 175 | 176 | if(file_ptr f{open(cwd.get(), init_path.data(), init_path.size(), 0)}; !!f) 177 | { 178 | process_init_file(cwd.get(), f.get()); 179 | return 0; 180 | } 181 | 182 | print_strings("Can't find init.sys!\n"); 183 | return -1; 184 | } -------------------------------------------------------------------------------- /drivers/cpu/madt.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | struct __attribute__((packed)) acpi_rsdp 12 | { 13 | char signature[8]; 14 | uint8_t checksum; 15 | char oem_id[6]; 16 | uint8_t revision; 17 | uint32_t rsdt_addr; 18 | }; 19 | 20 | struct __attribute__((packed)) acpi_sdt 21 | { 22 | char signature[4]; 23 | uint32_t length; 24 | uint8_t revision; 25 | uint8_t checksum; 26 | char oem_id[6]; 27 | char oem_table_id[8]; 28 | uint32_t oem_revision; 29 | char creator_id[4]; 30 | uint32_t creator_revision; 31 | }; 32 | 33 | struct __attribute__((packed)) acpi_rsdt 34 | { 35 | acpi_sdt header; 36 | uint32_t sdt_ptr[]; 37 | }; 38 | 39 | uintptr_t create_mapping(uintptr_t physical, size_t num_pages, 40 | page_flags_t flags) 41 | { 42 | return (uintptr_t)memmanager_map_to_new_pages(physical & ~(PAGE_SIZE - 1), 43 | num_pages, flags) + 44 | (physical & (PAGE_SIZE - 1)); 45 | } 46 | 47 | bool checksum_valid(uintptr_t addr, size_t size) 48 | { 49 | auto ptr = std::bit_cast(addr); 50 | return std::accumulate(ptr, ptr + size, (uint8_t)0) == 0; 51 | } 52 | 53 | acpi_rsdp* get_rsdp() 54 | { 55 | auto bda = create_mapping(0, 1, PAGE_PRESENT | PAGE_RW); 56 | 57 | printf("Searching EBDA\n"); 58 | 59 | auto ebda_addr = 60 | static_cast(read_addr(bda + 0x40e)) * 16; 61 | 62 | auto ebda = create_mapping(ebda_addr, 1, PAGE_PRESENT); 63 | 64 | for(auto addr = ebda; addr < ebda + 0x400; addr += 0x10) 65 | { 66 | if(memcmp((void*)addr, "RSD PTR ", 8) == 0 && checksum_valid(addr, 20)) 67 | { 68 | return std::bit_cast(addr); 69 | } 70 | } 71 | 72 | printf("Searching bios ROM\n"); 73 | 74 | auto bios_rom = create_mapping(0xE0000, 0x20, PAGE_PRESENT); 75 | 76 | for(auto addr = bios_rom; addr < bios_rom + 0x20000; addr += 0x10) 77 | { 78 | if(memcmp((void*)addr, "RSD PTR ", 8) == 0 && checksum_valid(addr, 20)) 79 | { 80 | return std::bit_cast(addr); 81 | } 82 | } 83 | 84 | printf("Can't find rsdp\n"); 85 | 86 | return nullptr; 87 | } 88 | 89 | uintptr_t acpi_get_table_addr(const char signature[4], int index) 90 | { 91 | auto rsdp = get_rsdp(); 92 | 93 | if(!rsdp) return 0; 94 | 95 | auto rsdt = 96 | (acpi_rsdt*)create_mapping((uintptr_t)rsdp->rsdt_addr, 0x1, PAGE_PRESENT); 97 | 98 | size_t num_entries = (rsdt->header.length - sizeof(acpi_sdt)) / 4; 99 | 100 | size_t num_found = 0; 101 | 102 | for(size_t i = 0; i < num_entries; i++) 103 | { 104 | auto ptr = (acpi_sdt*)create_mapping((uintptr_t)rsdt->sdt_ptr[i], 1, 105 | PAGE_PRESENT); 106 | 107 | if(!memcmp(ptr->signature, &signature[0], sizeof(ptr->signature)) && 108 | checksum_valid(std::bit_cast(ptr), ptr->length) && num_found++ == index) 109 | { 110 | printf("Found MADT\n"); 111 | 112 | return std::bit_cast(ptr); 113 | } 114 | } 115 | 116 | return 0; 117 | } 118 | 119 | struct __attribute__((packed)) madt 120 | { 121 | acpi_sdt header; 122 | uint32_t lapic_address; 123 | uint32_t flags; 124 | char entries[]; 125 | }; 126 | 127 | struct __attribute__((packed)) madt_header 128 | { 129 | uint8_t type; 130 | uint8_t length; 131 | }; 132 | 133 | struct __attribute__((packed)) madt_lapic 134 | { 135 | madt_header header; 136 | uint8_t acpi_processor_uid; 137 | uint8_t lapic_id; 138 | uint32_t flags; 139 | } ; 140 | 141 | extern "C" void madt_init() 142 | { 143 | auto table_addr = acpi_get_table_addr("APIC", 0); 144 | madt* table = std::bit_cast(table_addr); 145 | 146 | if(!table) return; 147 | 148 | std::vector cores; 149 | 150 | for(auto madt_addr = std::bit_cast(&table->entries[0]); 151 | madt_addr < table_addr + table->header.length;) 152 | { 153 | auto header = read_addr(madt_addr); 154 | 155 | if(read_addr(madt_addr).type == 0) 156 | { 157 | madt_lapic lapic = read_addr(madt_addr); 158 | 159 | if((lapic.flags & 1) ^ ((lapic.flags >> 1) & 1)) 160 | { 161 | cores.emplace_back(lapic.lapic_id); 162 | } 163 | } 164 | 165 | madt_addr += header.length; 166 | } 167 | 168 | init_smp(table->lapic_address, cores); 169 | } -------------------------------------------------------------------------------- /clib/include/string386.inl: -------------------------------------------------------------------------------- 1 | 2 | static inline void* __do_memcpy(void* dest, const void* src, size_t num) 3 | { 4 | void* od = dest; 5 | uint32_t temp; 6 | __asm__ volatile( 7 | " mov %%ecx, %[tmp]\n" 8 | " shr $0x2, %%ecx\n" 9 | " and $0x3, %[tmp]\n" 10 | " cld\n" 11 | " rep movsl\n" 12 | " mov %[tmp], %%ecx\n" 13 | " rep movsb\n" 14 | : "+D"(dest), "+S" (src), "+c" (num), [tmp]"=&r"(temp) // output 15 | : // input 16 | : "cc", "memory" // clobbered register 17 | ); 18 | return od; 19 | } 20 | 21 | static inline void* __do_memcpy4(void* dest, const void* src, size_t num) 22 | { 23 | num /= 4; 24 | 25 | void* od = dest; 26 | __asm__ volatile( 27 | " cld\n" 28 | " rep movsl\n" 29 | : "+D"(dest), "+S" (src), "+c" (num) // output 30 | : // input 31 | : "cc", "memory" // clobbered register 32 | ); 33 | 34 | return od; 35 | } 36 | 37 | static inline void* __do_memcpy_const_sz(void* dest, const void* src, size_t num) 38 | { 39 | size_t size_4 = num / 4; 40 | size_t size_x = num & 3; 41 | 42 | void* od = dest; 43 | __asm__ volatile( 44 | " cld\n" 45 | " rep movsl\n" 46 | " mov %3, %%ecx\n" 47 | " rep movsb\n" 48 | : "+D"(dest), "+S"(src), "+c"(size_4) // output 49 | : "ri"(size_x) // input 50 | : "cc", "memory" // clobbered register 51 | ); 52 | return od; 53 | } 54 | 55 | static inline void* memcpy(void* dst, const void* src, size_t size) 56 | { 57 | if(__builtin_constant_p(size)) 58 | { 59 | if(size <= sizeof(uintptr_t)) 60 | { 61 | return __builtin_memcpy(dst, src, size); 62 | } 63 | else if((size & 3) == 0) 64 | { 65 | return __do_memcpy4(dst, src, size); 66 | } 67 | else 68 | { 69 | return __do_memcpy_const_sz(dst, src, size); 70 | } 71 | } 72 | 73 | if(__builtin_constant_p(size & 3) && (size & 3) == 0) 74 | { 75 | return __do_memcpy4(dst, src, size); 76 | } 77 | 78 | return __do_memcpy(dst, src, size); 79 | } 80 | 81 | static inline void* __do_memset4(void* dest, int val, size_t num) 82 | { 83 | num /= 4; 84 | const uint32_t value = (uint32_t)val & 0xFF; 85 | const uint32_t v16 = (value << 8) | value; 86 | const uint32_t v = (v16 << 16) | v16; 87 | 88 | void* od = dest; 89 | __asm__ volatile( 90 | " cld\n" 91 | " rep stosl\n" 92 | : "+D"(dest), "+c" (num) // output 93 | : "a"(v) // input 94 | : "cc", "memory" // clobbered register 95 | ); 96 | return od; 97 | } 98 | 99 | static inline void* __do_memset_const_sz(void* dest, int val, size_t num) 100 | { 101 | const uint32_t value = (uint32_t)val & 0xFF; 102 | const uint32_t v16 = (value << 8) | value; 103 | const uint32_t v = (v16 << 16) | v16; 104 | 105 | size_t size_4 = num / 4; 106 | size_t size_x = num & 3; 107 | 108 | void* od = dest; 109 | __asm__ volatile( 110 | " cld\n" 111 | " rep stosl\n" 112 | " mov %2, %%ecx\n" 113 | " rep stosb\n" 114 | : "+D"(dest), "+c"(size_4) // output 115 | : "g"(size_x), "a"(v) // input 116 | : "cc", "memory" // clobbered register 117 | ); 118 | return od; 119 | } 120 | 121 | static inline void* __do_memset(void* dest, int val, size_t num) 122 | { 123 | const uint32_t value = (uint32_t)val & 0xFF; 124 | const uint32_t v16 = (value << 8) | value; 125 | const uint32_t v = (v16 << 16) | v16; 126 | 127 | void* od = dest; 128 | uint32_t temp; 129 | __asm__ volatile( 130 | " mov %%ecx, %[tmp]\n" 131 | " shr $0x2, %%ecx\n" 132 | " and $0x3, %[tmp]\n" 133 | " cld\n" 134 | " rep stosl\n" 135 | " mov %[tmp], %%ecx\n" 136 | " rep stosb\n" 137 | : "+D"(dest), "+c"(num), [tmp] "=&r"(temp) // output 138 | : "a"(v) // input 139 | : "cc", "memory" // clobbered register 140 | ); 141 | return od; 142 | } 143 | 144 | static inline void* memset(void* a, int value, size_t size) 145 | { 146 | if(__builtin_constant_p(size)) 147 | { 148 | if(size <= sizeof(uintptr_t)) 149 | { 150 | return __builtin_memset(a, value, size); 151 | } 152 | else if((size & 3) == 0) 153 | { 154 | return __do_memset4(a, value, size); 155 | } 156 | else 157 | { 158 | return __do_memset_const_sz(a, value, size); 159 | } 160 | } 161 | 162 | if(__builtin_constant_p(size & 3) && (size & 3) == 0) 163 | { 164 | return __do_memset4(a, value, size); 165 | } 166 | 167 | return __do_memset(a, value, size); 168 | } -------------------------------------------------------------------------------- /drivers/cpu/lapic.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "lapic.h" 10 | 11 | #define ENABLE 0x00000100 // Unit Enable 12 | #define INIT 0x00000500 // INIT/RESET 13 | #define STARTUP 0x00000600 // Startup IPI 14 | #define DELIVS 0x00001000 // Delivery status 15 | #define ASSERT 0x00004000 // Assert interrupt (vs deassert) 16 | #define DEASSERT 0x00000000 17 | #define LEVEL 0x00008000 // Level triggered 18 | #define BCAST 0x00080000 // Send to all APICs, including self. 19 | #define BUSY 0x00001000 20 | #define FIXED 0x00000000 21 | #define X1 0x0000000B // divide counts by 1 22 | #define PERIODIC 0x00020000 // Periodic 23 | #define MASKED 0x00010000 // Interrupt masked 24 | 25 | enum lapic_reg : uint32_t 26 | { 27 | ID = (0x0020 / 4), // ID 28 | VERSION = (0x0030 / 4), // Version 29 | TASK_PRI = (0x0080 / 4), // Task Priority 30 | EOI = (0x00B0 / 4), // EOI 31 | SVR = (0x00F0 / 4), // Spurious Interrupt Vector 32 | ESR = (0x0280 / 4), // Error Status 33 | INT_COMMAND_LO = (0x0300 / 4), // Interrupt Command 34 | INT_COMMAND_HI = (0x0310 / 4), // Interrupt Command [63:32] 35 | TIMER = (0x0320 / 4), // Local Vector Table 0 (TIMER) 36 | PCINT = (0x0340 / 4), // Performance Counter LVT 37 | LINT0 = (0x0350 / 4), // Local Vector Table 1 (LINT0) 38 | LINT1 = (0x0360 / 4), // Local Vector Table 2 (LINT1) 39 | ERROR = (0x0370 / 4), // Local Vector Table 3 (ERROR) 40 | TICR = (0x0380 / 4), // Timer Initial Count 41 | TCCR = (0x0390 / 4), // Timer Current Count 42 | TDCR = (0x03E0 / 4) // Timer Divide Configuration 43 | }; 44 | 45 | sync::atomic_flag cpu_spinlock; 46 | 47 | void test_entry_point(size_t cpu_id) 48 | { 49 | cpu_entry_point(cpu_id, std::bit_cast(&cpu_spinlock)); 50 | 51 | assert(false); 52 | } 53 | 54 | static uint32_t lapic_read(uint32_t* base, uint32_t reg) 55 | { 56 | return __atomic_load_n(base + reg, __ATOMIC_SEQ_CST); 57 | } 58 | 59 | static void lapic_write(uint32_t* base, uint32_t reg, uint32_t value) 60 | { 61 | __atomic_store_n(base + reg, value, __ATOMIC_SEQ_CST); 62 | __atomic_load_n(base + (0x20 / 4), __ATOMIC_SEQ_CST); 63 | } 64 | 65 | struct __attribute__((packed)) ap_bootstrap_params 66 | { 67 | uint32_t page_dir; 68 | uint32_t entry_point; 69 | uint32_t processor_id; 70 | }; 71 | 72 | extern uint8_t _binary_ap_bootstrap_bin_start; 73 | extern uint8_t _binary_ap_bootstrap_bin_end; 74 | 75 | void init_smp(uintptr_t lapic_phys_addr, std::vector& cores) 76 | { 77 | uintptr_t ap_bootstrap_addr = 0x7000; 78 | size_t ap_bootstrap_size = 79 | &_binary_ap_bootstrap_bin_end - &_binary_ap_bootstrap_bin_start; 80 | 81 | size_t params_offset = ap_bootstrap_size - sizeof(ap_bootstrap_params); 82 | 83 | memcpy((void*)ap_bootstrap_addr, &_binary_ap_bootstrap_bin_start, 84 | ap_bootstrap_size); 85 | 86 | ap_bootstrap_params* params = 87 | std::bit_cast(ap_bootstrap_addr + params_offset); 88 | 89 | params->page_dir = std::bit_cast(get_page_directory()); 90 | params->entry_point = std::bit_cast(&test_entry_point); 91 | 92 | printf("pdir: %X\n", params->page_dir); 93 | 94 | auto lapic_addr = 95 | (uint32_t*)memmanager_map_to_new_pages(lapic_phys_addr & 96 | ~(PAGE_SIZE - 1), 97 | 1, PAGE_PRESENT) + 98 | (lapic_phys_addr & (PAGE_SIZE - 1)); 99 | 100 | auto my_id = lapic_read(lapic_addr, 0x20 / 4); 101 | 102 | printf("BSP id: %X\n", my_id); 103 | 104 | outb(0x70, 0x0F); 105 | outb(0x71, 0x0A); 106 | 107 | auto zero = 108 | (uintptr_t)memmanager_map_to_new_pages(0, 1, PAGE_PRESENT | PAGE_RW); 109 | 110 | auto wrv = (uint16_t*)(zero + ((0x40 << 4 | 0x67))); // Warm reset vector 111 | wrv[0] = 0; 112 | wrv[1] = ap_bootstrap_addr >> 4; 113 | 114 | for(auto cpu : cores) 115 | { 116 | if(cpu.lapic_id == my_id) continue; 117 | 118 | add_cpu(cpu.lapic_id); 119 | 120 | cpu_spinlock.test_and_set(); 121 | 122 | params->processor_id = cpu.lapic_id; 123 | 124 | printf("Starting: %X\n", cpu.lapic_id); 125 | 126 | lapic_write(lapic_addr, lapic_reg::INT_COMMAND_HI, cpu.lapic_id << 24); 127 | lapic_write(lapic_addr, lapic_reg::INT_COMMAND_LO, 128 | INIT | LEVEL | ASSERT); 129 | sysclock_sleep(200, MICROSECONDS); 130 | lapic_write(lapic_addr, lapic_reg::INT_COMMAND_LO, INIT | LEVEL); 131 | sysclock_sleep(100, MICROSECONDS); 132 | 133 | for(size_t i = 0; i < 2; i++) 134 | { 135 | lapic_write(lapic_addr, lapic_reg::INT_COMMAND_HI, 136 | cpu.lapic_id << 24); 137 | lapic_write(lapic_addr, lapic_reg::INT_COMMAND_LO, 138 | STARTUP | (ap_bootstrap_addr >> 12)); 139 | sysclock_sleep(200, MICROSECONDS); 140 | } 141 | 142 | while(cpu_spinlock.test()); 143 | } 144 | } -------------------------------------------------------------------------------- /clib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | char* strchr(const char* str, int character) 6 | { 7 | while (*str != (char)character) 8 | { 9 | if (*str == '\0') 10 | { 11 | return NULL; 12 | } 13 | str++; 14 | } 15 | return (char*)str; 16 | } 17 | 18 | char* strrchr(const char* str, int character) 19 | { 20 | for(const char* ptr = str + strlen(str); ptr >= str; --ptr) 21 | { 22 | if(*ptr == (char)character) 23 | { 24 | return (char*)ptr; 25 | } 26 | } 27 | return NULL; 28 | } 29 | 30 | char* strtok(char* str, const char* delimiters) 31 | { 32 | static char* buffer = NULL; 33 | 34 | if(str != NULL) 35 | { 36 | buffer = str; 37 | } 38 | if(buffer == NULL || buffer[0] == '\0') 39 | { 40 | return NULL; 41 | } 42 | 43 | char *token = buffer; 44 | char *c = buffer; 45 | 46 | for(; *c != '\0'; c++) 47 | { 48 | const char *dchar = delimiters; 49 | for(; *dchar != '\0'; dchar++) 50 | { 51 | if(*c == *dchar) 52 | { 53 | *c = '\0'; 54 | buffer = c + 1; 55 | 56 | if(c == token) 57 | { 58 | token++; 59 | continue; 60 | } 61 | return token; 62 | } 63 | } 64 | } 65 | 66 | return token; 67 | } 68 | 69 | int strcmp(const char* s1, const char* s2) 70 | { 71 | while(*s1 && (*s1 == *s2)) 72 | { 73 | s1++; 74 | s2++; 75 | } 76 | return *(const unsigned char*)s1 - *(const unsigned char*)s2; 77 | } 78 | 79 | //void* memcpy(void* dest, const void* src, size_t num) 80 | //{ 81 | // char* dst8 = (char*)dest; 82 | // char* src8 = (char*)src; 83 | // 84 | // while(num--) 85 | // { 86 | // *dst8++ = *src8++; 87 | // } 88 | // return dest; 89 | //} 90 | 91 | int memcmp(const void* ptr1, const void* ptr2, size_t num) 92 | { 93 | if(!num) return 0; 94 | 95 | const unsigned char* ptra = (const unsigned char*)ptr1; 96 | const unsigned char* ptrb = (const unsigned char*)ptr2; 97 | 98 | while(--num && *ptra == *ptrb) 99 | { 100 | ptra++; 101 | ptrb++; 102 | } 103 | 104 | return (*((unsigned char*)ptra) - *((unsigned char*)ptrb)); 105 | } 106 | 107 | /* 108 | void* memset(void* ptr, int value, size_t num) 109 | { 110 | uint8_t u8 = (uint8_t)value; 111 | uint8_t* sp = (uint8_t*)ptr; 112 | 113 | while(((uint32_t)sp & (sizeof(uint32_t) - 1)) && num--) 114 | { 115 | *sp++ = u8; 116 | } 117 | 118 | uint32_t u32 = (uint32_t)value & 0xff; 119 | u32 = (u32 << 24) | (u32 << 16) | (u32 << 8) | u32; 120 | uint32_t* lp = (uint32_t*)sp; 121 | 122 | while(num / sizeof(uint32_t)) 123 | { 124 | *lp++ = u32; 125 | num -= sizeof(uint32_t); 126 | } 127 | 128 | sp = (uint8_t*)lp; 129 | 130 | while(num--) 131 | { 132 | *sp++ = u8; 133 | } 134 | 135 | return ptr; 136 | }*/ 137 | 138 | //void* memset(void* ptr, int value, size_t num) 139 | //{ 140 | // unsigned char* ptr8 = (unsigned char*)ptr; 141 | // 142 | // while(num--) 143 | // { 144 | // *ptr8++ = (unsigned char)value; 145 | // } 146 | // return ptr; 147 | //} 148 | 149 | size_t strlen(const char* str) 150 | { 151 | size_t len = 0; 152 | 153 | while(*(str++) != '\0') { len++; } 154 | 155 | return len; 156 | } 157 | 158 | int strncmp(const char* s1, const char* s2, size_t count) 159 | { 160 | while(count-- && *s1 && (*s1 == *s2)) 161 | { 162 | s1++; 163 | s2++; 164 | } 165 | return *(const unsigned char*)s1 - *(const unsigned char*)s2; 166 | } 167 | 168 | char* strcat(char* destination, const char* source) 169 | { 170 | memcpy(destination + strlen(destination), source, strlen(source) + 1); 171 | return destination; 172 | } 173 | 174 | char* strcpy(char* destination, const char* source) 175 | { 176 | memcpy(destination, source, strlen(source) + 1); 177 | return destination; 178 | } 179 | 180 | char* strncpy(char* dst, const char* src, size_t count) 181 | { 182 | if(dst == NULL) 183 | { 184 | return NULL; 185 | } 186 | 187 | char* dst_ptr = dst; 188 | 189 | while(*src && count) 190 | { 191 | *dst_ptr++ = *src++; 192 | count--; 193 | } 194 | 195 | if(count) 196 | *dst_ptr = '\0'; 197 | 198 | return dst; 199 | } 200 | 201 | void* memmove(void* dest, const void* src, size_t num) 202 | { 203 | uint8_t* dst_ptr = dest; 204 | const uint8_t* src_ptr = src; 205 | 206 | if(src_ptr < dst_ptr && dst_ptr < src_ptr + num) 207 | { 208 | src_ptr += num; 209 | dst_ptr += num; 210 | while(num--) 211 | { 212 | *--dst_ptr = *--src_ptr; 213 | } 214 | } 215 | else 216 | { 217 | while(num--) 218 | { 219 | *dst_ptr++ = *src_ptr++; 220 | } 221 | } 222 | 223 | return dest; 224 | } 225 | 226 | void* memchr(const void* str, int c, size_t n) 227 | { 228 | if(!str) return NULL; 229 | 230 | char* p = (char*)str; 231 | while(n--) 232 | { 233 | if(*p != (char)c) 234 | { 235 | p++; 236 | } 237 | else 238 | { 239 | return p; 240 | } 241 | } 242 | return NULL; 243 | } 244 | --------------------------------------------------------------------------------