From 5971218b566983410989ab451fd5daa541f3d5d6 Mon Sep 17 00:00:00 2001 From: David Goeke Date: Fri, 20 Mar 2026 16:57:08 -0500 Subject: [PATCH] Espresso 0.0.2c --- .gitignore | 20 ++ FEATURES.md | 15 ++ Makefile | 24 +- TODO.md | 24 ++ arch/x86/exec/secf.s | 18 ++ arch/x86/isr.asm | 231 +++++++++--------- boot/dump.txt | 386 ++++++++++++++++++++++++++++++ drivers/audio/pcspeaker.c | 46 ++++ drivers/elf.c | 18 +- drivers/exec/secf.c | 48 ++++ drivers/fs/ekfs.c | 49 ++++ drivers/fs/fat16.c | 374 +++++++++++++++++++++++++++++ drivers/fs/vfs.c | 80 ++++++- drivers/gdt.c | 4 +- drivers/idt.c | 225 ++++++++++------- drivers/irq.c | 70 ++++-- drivers/keyboard.c | 148 ++++++++++++ drivers/new_tty.c | 382 +++++++++++++++++++++++++++++ drivers/pit.c | 22 +- drivers/ps2_keyboard.c | 180 ++++++++------ drivers/tty.c | 9 + files/idt.c | 177 ++++++++++++++ files/idt.h | 18 ++ files/irq.c | 69 ++++++ files/irq.h | 43 ++++ files/isr.asm | 154 ++++++++++++ files/kernel.c | 164 +++++++++++++ files/pit.c | 62 +++++ files/scheduler.c | 158 ++++++++++++ files/scheduler.h | 32 +++ include/arch/x86/intrin.h | 15 ++ include/drivers/audio/pcspeaker.h | 11 + include/drivers/elf.h | 48 ++-- include/drivers/idt.h | 7 +- include/drivers/irq.h | 23 +- include/drivers/keyboard.h | 10 + include/drivers/pit.h | 5 +- include/drivers/ps2_keyboard.h | 4 +- include/fs/ekfs.h | 37 +++ include/fs/fat16.h | 78 ++++++ include/kernel/kshell.h | 4 +- include/kernel/syscall.h | 111 +++++++++ include/kincl.h | 13 +- include/math/random.h | 15 ++ include/new_tty.h | 73 ++++++ include/printf.h | 4 +- include/processes.h | 12 +- include/scheduler.h | 21 ++ include/stdio.h | 13 + include/string.h | 4 +- include/sync.h | 14 ++ include/tty.h | 7 +- include/types.h | 20 ++ kernel/intro.c | 8 +- kernel/kernel.c | 88 ++++--- kernel/kshell.c | 230 ++++++++++++++---- kernel/syscall.c | 118 +++++++++ kincl.h | 6 - lib/espresso/kstring.c | 58 +++++ lib/math/random.c | 79 ++++++ lib/mm/heap.c | 7 +- lib/mm/pmm.c | 24 ++ lib/printf.c | 2 + lib/processes.c | 13 +- lib/scheduler.c | 76 ++++++ lib/stdio.c | 94 +++++--- lib/string.c | 47 +++- lib/sync.c | 40 ++++ lib/vector_extensions/sse.c | 4 + libc/include/stdio.h | 9 + libc/include/string.h | 19 ++ libc/stdio.c | 22 ++ libc/string.c | 125 ++++++++++ syscall.h | 110 +++++++++ usefull_gcc_stuff.txt.junk | 3 + user/hello.elf | Bin 0 -> 2128 bytes user/test.c | 75 ++++++ 77 files changed, 4538 insertions(+), 518 deletions(-) create mode 100644 .gitignore create mode 100644 FEATURES.md create mode 100644 TODO.md create mode 100644 arch/x86/exec/secf.s create mode 100644 boot/dump.txt create mode 100644 drivers/audio/pcspeaker.c create mode 100644 drivers/exec/secf.c create mode 100644 drivers/fs/ekfs.c create mode 100644 drivers/fs/fat16.c create mode 100644 drivers/keyboard.c create mode 100644 drivers/new_tty.c create mode 100644 files/idt.c create mode 100644 files/idt.h create mode 100644 files/irq.c create mode 100644 files/irq.h create mode 100644 files/isr.asm create mode 100644 files/kernel.c create mode 100644 files/pit.c create mode 100644 files/scheduler.c create mode 100644 files/scheduler.h create mode 100644 include/arch/x86/intrin.h create mode 100644 include/drivers/audio/pcspeaker.h create mode 100644 include/drivers/keyboard.h create mode 100644 include/fs/ekfs.h create mode 100644 include/fs/fat16.h create mode 100644 include/kernel/syscall.h create mode 100644 include/math/random.h create mode 100644 include/new_tty.h create mode 100644 include/scheduler.h create mode 100644 include/sync.h create mode 100644 kernel/syscall.c delete mode 100644 kincl.h create mode 100644 lib/espresso/kstring.c create mode 100644 lib/math/random.c create mode 100644 lib/scheduler.c create mode 100644 lib/sync.c create mode 100644 libc/include/stdio.h create mode 100644 libc/include/string.h create mode 100644 libc/stdio.c create mode 100644 libc/string.c create mode 100644 syscall.h create mode 100644 usefull_gcc_stuff.txt.junk create mode 100755 user/hello.elf create mode 100644 user/test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..012ce6a --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# probably don't change this? IDK let me know + +# might include some of these types of files later??? +*.sh + + +.* +*.a +*.o +*.exe +*.so +*.log + +# I don't think we'll being including compressed files in the repo... +*.zip +*.tar +*.gz +*.xz + +!.gitignore diff --git a/FEATURES.md b/FEATURES.md new file mode 100644 index 0000000..0a58186 --- /dev/null +++ b/FEATURES.md @@ -0,0 +1,15 @@ +Features that the Espresso kernel currently has. +Might not be up-to-date, though should be. + +General: + Syscalls via int 16 (decimal) + + +Input/Output: + TTY driver (which works thank goodness) + Keyboard driver (meager, but usable) + Very stupid terminal text output drivers (files need renaming, confusing when comparing tty.c to new_tty.c) + + +Filesystems: + FAT16 (no directory support yet) diff --git a/Makefile b/Makefile index 14d27e8..edec03f 100644 --- a/Makefile +++ b/Makefile @@ -1,18 +1,19 @@ # === Config === TARGET := boot/espresso.elf ISO := boot/espresso.iso +FAT16_DISK := espresso.img CC := i686-elf-gcc AS := i686-elf-as NASM := nasm -QEMU_MKE_IMG := qemu-img create -f raw espresso.img 64M +QEMU_MKE_IMG := qemu-img create -f raw $(FAT16_DISK) 64M MKFS_VFAT := sudo mkfs.vfat MKFS_FLAGS := -F 16 -S 512 NASMFLAGS := -f elf32 WNOFLAGS := -Wno-discarded-qualifiers CFLAGS := -std=gnu99 -ffreestanding -O2 -Wall -Wextra -msse $(WNOFLAGS) -nostdlib -nostartfiles -include include/kincl.h LDFLAGS := -T linker.ld -ffreestanding -O2 -nostdlib -nostartfiles -QEMUFLAGS := -boot d -cdrom $(ISO) -drive file=espresso.img,format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1 -QEMUFLGS_EXT := -vga std -d int,cpu_reset -D qemu.log -no-reboot #-singlestep +QEMUFLAGS := -no-shutdown -boot d -cdrom $(ISO) -drive file=$(FAT16_DISK),format=raw,if=ide,readonly=off,rerror=report,werror=report -cpu qemu32,sse4.1 +QEMUFLGS_EXT := -vga std -d int,cpu_reset -D qemu.log # -audiodev pa,id=speaker -machine pcspk-audiodev=speaker MOR_QEMUFLGS := -net none -netdev user,id=n0 -device rtl8139,netdev=n0 -serial file:serial.log SRC_DIRS := kernel drivers lib INCLUDE_DIRS := include @@ -78,10 +79,10 @@ iso: $(TARGET) # === Run in QEMU === run: iso - @if [ ! -f espresso.img ]; then \ + @if [ ! -f $(FAT16_DISK) ]; then \ $(QEMU_MKE_IMG); \ + sudo mkfs.fat $(MKFS_FLAGS) espresso.img; \ fi - sudo mkfs.fat $(MKFS_FLAGS) espresso.img @echo qemu-system-i386 $(QEMUFLAGS) $(QEMUFLGS_EXT) $(MOR_QEMUFLGS) @@ -90,6 +91,17 @@ run: iso clean: rm -f $(INTERNAL_OBJS) $(TARGET) $(ISO) rm -rf $(ISO_DIR) + +clean_disk: rm -f espresso.img -.PHONY: all clean iso run debug build buildc +# === Push code to repo === +commit: +ifndef MSG + $(error MSG required) +endif + git add . + git commit -m "$(MSG)" + git push + +.PHONY: all clean clean_disk iso run debug build buildc diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..85885f9 --- /dev/null +++ b/TODO.md @@ -0,0 +1,24 @@ +Here are some of the things I think I/we should add to Espresso, in no particular order. + + +Important objectives: + More syscalls + Better C libs (both kernel and user) + VFS (Virtual FileSystem) + Scheduler (very important!) + +General objectives: + More filesystems + PAE support + Better MM system + More CPU extentions, like AVX (if possible), more SSE, MMX, etc. + Better random number generation + Time system (probably use CMOS clock and stuff) + + +More in the future objectives: + VGA support + Mouse support + USB support + GPU support + Windowing compositor/desktop diff --git a/arch/x86/exec/secf.s b/arch/x86/exec/secf.s new file mode 100644 index 0000000..ea0048e --- /dev/null +++ b/arch/x86/exec/secf.s @@ -0,0 +1,18 @@ +/* see drivers/exec/secf.c for info on SECF */ + + +.global _exec +.type _exec, @function + +/* XXX: YOU NEED TO SAVE REGISTERS BEFORE CALLING THIS FUNCTION!!! THIS FUNCTION OVERWRITES REGISTERS!!! :XXX */ +/* args (C style): void* var_area_ptr, char* arg_str, int arg_str_len, int var_area_size, void* entry_func_ptr */ +_exec: + pop %edx /* var_area_ptr */ + pop %esi /* arg_str */ + pop %ecx /* arg_str_len */ + pop %ebp /* var_area_size */ + pop %eax /* entry_func_ptr */ + + call %eax + + ret diff --git a/arch/x86/isr.asm b/arch/x86/isr.asm index 6513859..77dd1ce 100644 --- a/arch/x86/isr.asm +++ b/arch/x86/isr.asm @@ -1,163 +1,152 @@ [BITS 32] + [GLOBAL isr_stub_table] [GLOBAL irq_stub_table] -extern irq_handler ; C function +[GLOBAL interrupt_entry] + +extern interrupt_dispatcher section .text -; -------------------------------------------- -; ------------------- IRQs ------------------- -; -------------------------------------------- +; ============================================================ +; COMMON INTERRUPT ENTRY +; ============================================================ -%macro irq_stub 1 -irq_stub_%+%1: - pusha - push ds - push es - push fs +interrupt_entry: + + ; Stack already contains: + ; err_code + ; int_no + ; eip + ; cs + ; eflags + + pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi + push gs + push fs + push es + push ds - mov ax, 0x10 + mov ax, 0x10 ; load kernel data selector mov ds, ax mov es, ax mov fs, ax mov gs, ax - push dword %1 ; Push IRQ number - call irq_handler - add esp, 4 ; Clean up stack + push esp ; pass pointer to registers_t + call interrupt_dispatcher + add esp, 4 ; I don't remember what this does... but don't remove it + ; NVM, I remember: it cleans up the registers_t* argument we passed to interrupt_dispatcher - ; Send EOI - mov al, 0x20 - mov bl, %1 - cmp bl, 8 - jb .skip_slave_eoi - out 0xA0, al -.skip_slave_eoi: - out 0x20, al + ; don't do this yet, it corrupts stuff. wait until the scheduler is finished + ;mov esp, eax ; move the new stack pointer into esp pop gs pop fs pop es pop ds + popa - iret + + add esp, 8 ; remove int_no + err_code + + iret ; return from interrupt + + +; ============================================================ +; IRQ STUBS +; ============================================================ + +%macro IRQ 1 +irq_stub_%+%1: + push dword 0 ; fake error code + push dword (32 + %1) ; vector number + jmp interrupt_entry %endmacro - -; Define 16 IRQ stubs -irq_stub 0 -irq_stub 1 -irq_stub 2 -irq_stub 3 -irq_stub 4 -irq_stub 5 -irq_stub 6 -irq_stub 7 -irq_stub 8 -irq_stub 9 -irq_stub 10 -irq_stub 11 -irq_stub 12 -irq_stub 13 -irq_stub 14 -irq_stub 15 +IRQ 0 +IRQ 1 +IRQ 2 +IRQ 3 +IRQ 4 +IRQ 5 +IRQ 6 +IRQ 7 +IRQ 8 +IRQ 9 +IRQ 10 +IRQ 11 +IRQ 12 +IRQ 13 +IRQ 14 +IRQ 15 +IRQ 16 +IRQ 17 +IRQ 18 +IRQ 19 irq_stub_table: %assign i 0 -%rep 16 +%rep 20 dd irq_stub_%+i %assign i i+1 %endrep -; -------------------------------------------- -; ------------------- ISRs ------------------- -; -------------------------------------------- -; Common exception handler entry point -isr_common_handler: - pusha ; Push general-purpose registers - push ds - push es - push fs - push gs +; ============================================================ +; EXCEPTION STUBS +; ============================================================ - ; Load known-good segment selectors - mov ax, 0x10 - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - ; Print exception number and error code - ; You can insert direct port writes or call kernel logging function here - ; For now, just hang -.halt: - cli - hlt - jmp .halt - - ; If you want to later restore: - pop gs - pop fs - pop es - pop ds - popa - add esp, 8 ; clean up int_no + err_code - iret - -; Macro: for exceptions with error code -%macro isr_err_stub 1 +%macro ISR_NOERR 1 isr_stub_%+%1: - cli - push dword %1 ; interrupt number - jmp isr_common_handler + push dword 0 ; fake error code + push dword %1 ; interrupt number + jmp interrupt_entry %endmacro -; Macro: for exceptions without error code -%macro isr_no_err_stub 1 +%macro ISR_ERR 1 isr_stub_%+%1: - cli - push dword 0 ; fake error code - push dword %1 ; interrupt number - jmp isr_common_handler + push dword %1 ; interrupt number + jmp interrupt_entry %endmacro -; Define all 32 exception stubs -isr_no_err_stub 0 -isr_no_err_stub 1 -isr_no_err_stub 2 -isr_no_err_stub 3 -isr_no_err_stub 4 -isr_no_err_stub 5 -isr_no_err_stub 6 -isr_no_err_stub 7 -isr_err_stub 8 -isr_no_err_stub 9 -isr_err_stub 10 -isr_err_stub 11 -isr_err_stub 12 -isr_err_stub 13 -isr_err_stub 14 -isr_no_err_stub 15 -isr_no_err_stub 16 -isr_err_stub 17 -isr_no_err_stub 18 -isr_no_err_stub 19 -isr_no_err_stub 20 -isr_no_err_stub 21 -isr_no_err_stub 22 -isr_no_err_stub 23 -isr_no_err_stub 24 -isr_no_err_stub 25 -isr_no_err_stub 26 -isr_no_err_stub 27 -isr_no_err_stub 28 -isr_no_err_stub 29 -isr_err_stub 30 -isr_no_err_stub 31 -; Create jump table +; Exceptions 0–31 + +ISR_NOERR 0 +ISR_NOERR 1 +ISR_NOERR 2 +ISR_NOERR 3 +ISR_NOERR 4 +ISR_NOERR 5 +ISR_NOERR 6 +ISR_NOERR 7 +ISR_ERR 8 +ISR_NOERR 9 +ISR_ERR 10 +ISR_ERR 11 +ISR_ERR 12 +ISR_ERR 13 +ISR_ERR 14 +ISR_NOERR 15 +ISR_NOERR 16 +ISR_ERR 17 +ISR_NOERR 18 +ISR_NOERR 19 +ISR_NOERR 20 +ISR_NOERR 21 +ISR_NOERR 22 +ISR_NOERR 23 +ISR_NOERR 24 +ISR_NOERR 25 +ISR_NOERR 26 +ISR_NOERR 27 +ISR_NOERR 28 +ISR_NOERR 29 +ISR_ERR 30 +ISR_NOERR 31 + isr_stub_table: %assign i 0 %rep 32 diff --git a/boot/dump.txt b/boot/dump.txt new file mode 100644 index 0000000..99efa6e --- /dev/null +++ b/boot/dump.txt @@ -0,0 +1,386 @@ +0020efdf 00000001 b capslock_pressed +0020e020 00000001 B char_entered +0020c034 00000001 d color +0020d000 00000001 b completed.2 +0020efd8 00000001 B current_char +0020e02c 00000001 b __debug +0020e024 00000001 B _debug +0020eb34 00000001 b duckfs_drive +0020efde 00000001 b extended +0020efdb 00000001 b gets_called +0020efda 00000001 b gets_finished +0020efdd 00000001 b is_new_char +0020efdc 00000001 b is_new_key +0020efe8 00000001 B pit_initialized +0020efd9 00000001 B ps2keyboard_initialized +0020eb38 00000001 B ramfs_initialized +00200230 00000001 T set_bit_bo +0020efe0 00000001 b shift_pressed +0020efa8 00000001 B terminal_color +00208d9a 00000002 T _cli_asm +0020efbc 00000002 B current_key +00208dc9 00000002 t .done +00208d96 00000002 T _halt_asm +00208d98 00000002 T _sti_asm +0020a052 00000003 r CSWTCH.121 +00208d93 00000003 T _hang_asm +00206a80 00000003 T load_elf32 +0020efc4 00000004 B capacity +0020eae4 00000004 b cluster_heap_lba +0020c010 00000004 D command +0020c04c 00000004 d __CTOR_END__ +0020c048 00000004 d __CTOR_LIST__ +0020eae0 00000004 b current_directory_cluster +0020efcc 00000004 B current_length +0020efd4 00000004 B current_string +0020c004 00000004 D __dso_handle +0020c054 00000004 D __DTOR_END__ +0020d004 00000004 b dtor_idx.1 +0020c050 00000004 d __DTOR_LIST__ +0020c00c 00000004 D espresso_str +0020eb30 00000004 b fat32_drive +0020eae8 00000004 b fat_start_lba +0020effc 00000004 b free_list +0020efc0 00000004 B gets_capacity +0020efc8 00000004 B gets_length +0020efd0 00000004 B gets_string +0020c03c 00000004 D _has_cpuid +0020c044 00000004 d _has_mmx +0020c040 00000004 d _has_sse +0020f004 00000004 b heap_base +0020f000 00000004 b heap_size +0020efb4 00000004 B hook_count +0020efb8 00000004 B hooks +0020c008 00000004 D kernel_version +0020c018 00000004 d next_fd +0020c038 00000004 D next_id +0020f00c 00000004 b next_token.0 +0020efa0 00000004 b num_irqs_missed +0020f008 00000004 b page_directory +0020e028 00000004 B prompt +0020eb3c 00000004 b ramfs_num_files +0020eb40 00000004 b ramfs_root +0020e8c8 00000004 B root +0020c014 00000004 D shell_version +0020c000 00000004 D sse_initialized +0020efa4 00000004 B terminal_buffer +0020efac 00000004 B terminal_column +0020efb0 00000004 B terminal_row +0020eff8 00000004 b total_pages +0020c030 00000004 d xorshift_state +00207f20 00000005 T atol +00206ad0 00000005 T gets +002091a6 00000005 t isr_stub_10 +002091ab 00000005 t isr_stub_11 +002091b0 00000005 t isr_stub_12 +002091b5 00000005 t isr_stub_13 +002091ba 00000005 t isr_stub_14 +0020919a 00000005 t isr_stub_8 +00208d80 00000005 T ksleep +00205ff0 00000005 T pci_init +00206380 00000006 T get_string +0020e040 00000006 B gp +0020e090 00000006 b idtr +002000a3 00000006 T _kernel_early +00203da0 00000006 T ramfs_get_files +00203d90 00000006 T ramfs_get_root +00205e00 00000006 T use_serial +0020009c 00000007 t .done +00209162 00000007 t isr_stub_0 +00209169 00000007 t isr_stub_1 +00209170 00000007 t isr_stub_2 +00209177 00000007 t isr_stub_3 +0020917e 00000007 t isr_stub_4 +00209185 00000007 t isr_stub_5 +0020918c 00000007 t isr_stub_6 +00209193 00000007 t isr_stub_7 +0020919f 00000007 t isr_stub_9 +00200f60 00000008 T clear_debug +00200f80 00000008 T get_debug +002091d3 00000008 t isr_stub_17 +00209253 00000008 t isr_stub_30 +0020eff0 00000008 B pit_ticks +00203db0 00000008 T ramfs_get_initialized +00200f50 00000008 T set_debug +0020c020 00000008 D sfs_next_free_data_sector +0020c028 00000008 d state +00205550 00000008 T terminal_getcolor +00200f70 00000008 T toggle_debug +00209535 0000000a T _fini +00208e08 0000000a t irq_stub_0.skip_slave_eoi +00208ffc 0000000a t irq_stub_10.skip_slave_eoi +0020902e 0000000a t irq_stub_11.skip_slave_eoi +00209060 0000000a t irq_stub_12.skip_slave_eoi +00209092 0000000a t irq_stub_13.skip_slave_eoi +002090c4 0000000a t irq_stub_14.skip_slave_eoi +002090f6 0000000a t irq_stub_15.skip_slave_eoi +00208e3a 0000000a t irq_stub_1.skip_slave_eoi +00208e6c 0000000a t irq_stub_2.skip_slave_eoi +00208e9e 0000000a t irq_stub_3.skip_slave_eoi +00208ed0 0000000a t irq_stub_4.skip_slave_eoi +00208f02 0000000a t irq_stub_5.skip_slave_eoi +00208f34 0000000a t irq_stub_6.skip_slave_eoi +00208f66 0000000a t irq_stub_7.skip_slave_eoi +00208f98 0000000a t irq_stub_8.skip_slave_eoi +00208fca 0000000a t irq_stub_9.skip_slave_eoi +002091bf 0000000a t isr_stub_15 +002091c9 0000000a t isr_stub_16 +002091db 0000000a t isr_stub_18 +002091e5 0000000a t isr_stub_19 +002091ef 0000000a t isr_stub_20 +002091f9 0000000a t isr_stub_21 +00209203 0000000a t isr_stub_22 +0020920d 0000000a t isr_stub_23 +00209217 0000000a t isr_stub_24 +00209221 0000000a t isr_stub_25 +0020922b 0000000a t isr_stub_26 +00209235 0000000a t isr_stub_27 +0020923f 0000000a t isr_stub_28 +00209249 0000000a t isr_stub_29 +0020925b 0000000a t isr_stub_31 +00200086 0000000a t .set_result +00200000 0000000c T __kernel_text_start +00200090 0000000c t .no_sse +00200240 0000000d T ack_char +0020005f 0000000d t .check_sse3 +00200079 0000000d t .check_sse41 +0020006c 0000000d t .check_ssse3 +00203bd0 0000000d T duckfs_set_drive +00205540 0000000d T terminal_setcolor +00208d85 0000000e T _enable_paging_asm +002092f0 0000000e T gdt_flush +00208dbb 0000000e t .no_cpuid +00209526 0000000f T _init +00209153 0000000f t isr_common_handler.halt +002014c0 0000000f T vga_entry_color +00206000 00000010 T read_ehci_register +00206030 00000011 T initialize_ehci +00208150 00000011 T printf_set_color +00203d00 00000011 T ramfs_init +0020a040 00000012 r CSWTCH.125 +002092fe 00000012 t gdt_flush.flush_label +002014d0 00000012 T vga_entry +00209140 00000013 t isr_common_handler +00206010 00000013 T write_ehci_register +00207d60 00000014 T ischar +00207e00 00000014 T isprint +00207da0 00000014 T lower +00200440 00000014 T start_kernel_shell +00207de0 00000014 T tolower +00207dc0 00000014 T toupper +00207d80 00000014 T upper +00206a90 00000015 T getchar +00206ab0 00000015 T getstring +00208c60 00000015 T sleep +00208dcb 00000015 t _sse_level +00207220 00000016 T enable_sse +002075f0 00000017 T int_vector_to_double_vector +00207d40 00000017 T isalpha +0020d008 00000018 b object.0 +002055a0 00000018 T terminal_clear +00205400 00000019 T set_irq_handler +00205310 0000001a T read_sector +00207160 0000001a T ulrand +00205330 0000001a T write_sector +002075d0 0000001b T double_vector_to_int_vector +00207d20 0000001b T isspace +002076c0 0000001b T strlen +00200210 0000001c T init_vars +00205de0 0000001c T serial_read +00206320 0000001d T get_char +00206a20 0000001d T pit_handler +00206a00 0000001d T pit_init +00207140 0000001d T uirand_range +00208d9c 0000001f t _init_cpuid +00205d60 0000001f T serial_write +002000a9 00000020 T _start +00206c60 00000023 T pmm_free_page +0020933a 00000025 t @@ +00207840 00000025 T strcpy +002071e0 00000026 T decode_float +00208d50 00000026 T make_process +00209389 00000027 t m +0020e060 00000028 B gdt +00208de0 00000028 t irq_stub_0 +00208e12 00000028 t irq_stub_1 +00208fd4 00000028 t irq_stub_10 +00209006 00000028 t irq_stub_11 +00209038 00000028 t irq_stub_12 +0020906a 00000028 t irq_stub_13 +0020909c 00000028 t irq_stub_14 +002090ce 00000028 t irq_stub_15 +00208e44 00000028 t irq_stub_2 +00208e76 00000028 t irq_stub_3 +00208ea8 00000028 t irq_stub_4 +00208eda 00000028 t irq_stub_5 +00208f0c 00000028 t irq_stub_6 +00208f3e 00000028 t irq_stub_7 +00208f70 00000028 t irq_stub_8 +00208fa2 00000028 t irq_stub_9 +0020e8a0 00000028 b super +00205970 00000028 T terminal_writechar_r +00209310 0000002a T _get_fonts_asm +0020935f 0000002a t _set_fonts_asm +00207bd0 0000002b T memcpy +002080c0 0000002b T printd +00206060 0000002c T keyboard_init +0020eb00 00000030 b bpb +0020a240 00000030 r ps_of_two +00207080 00000034 T seed_rand +00205560 00000036 T terminal_putentryat +00201370 00000038 T idt_set_descriptor +00206a40 00000039 T pit_sleep +00205e10 0000003a T pci_config_read +00207b40 0000003c T strchr +00206340 0000003d T get_key +00205e50 0000003d T pci_config_write +00205930 0000003d T terminal_write +002059a0 0000003d T terminal_writestring +00207e20 0000003e T lowers +00205ca0 0000003e T terminal_update_cursor +00207e60 0000003e T uppers +002053c0 0000003f T irq_handler +00208c80 0000003f T is_low_power_of_two +002013b0 0000003f T pic_remap +00208c20 0000003f T printwc +002000d0 00000040 t deregister_tm_clones +002093b0 00000040 t __do_global_ctors_aux +002001d0 00000040 t frame_dummy +00209100 00000040 T irq_stub_table +0020a000 00000040 R __kernel_rodata_start +00200110 00000040 t register_tm_clones +00206780 00000041 T free_current_string +00207b80 00000042 T memset +002072e0 00000044 T sse2_add_double_arrays +00207380 00000044 T sse2_add_int32_arrays +00207330 00000044 T sse2_add_int64_arrays +00207c00 00000046 T memcmp +00207740 00000049 T strncmp +00204350 0000004b T ramfs_resolve_fd +00201040 0000004d T print_gprs +002059e0 0000004d T terminal_writeline +00205360 00000051 T irq_init +0020000c 00000053 t enable_sse_asm +002080f0 00000053 T printdc +002054e0 00000053 T terminal_initialize +00207180 00000053 T ulrand_range +00206db0 00000054 T free +002076e0 00000054 T strcmp +00206e10 00000055 T calloc +002005c0 00000057 T clear_bss +00201770 00000057 T duckfs_mount +00201e60 00000057 T duckfs_read_file +00207c50 00000057 T memclr +002003e0 00000058 T intro_begin +00205d80 0000005d T serial_puts +00202ce0 00000060 T print_83 +00206f70 00000063 T paging_init +00207900 00000064 T strcat +002062b0 00000067 T call_hooks +00203d20 00000068 T ramfs_make_root +00207cb0 0000006a T memmove +00203f50 0000006b T ramfs_read_file +00207ea0 00000072 T atoi +00205ce0 00000072 T serial_init +00205660 00000072 T terminal_scroll +00202b30 00000074 t find_free_cluster +0020a270 00000074 r __FRAME_END__ +00205c20 00000078 T terminal_set_cursor +00206c90 0000007a T heap_init +00206be0 0000007a T pmm_alloc_page +00206ef0 0000007b T map_page +00201500 0000007e t duckfs_alloc_block +00205a30 0000007e T terminal_debug_writestring +002070c0 0000007f T uirand +00200150 00000080 t __do_global_dtors_aux +00206e70 00000080 T realloc +0020a060 00000080 r scancode_map +00203be0 00000082 T disk_read +00203c70 00000082 T disk_write +00207870 00000089 T strncpy +00209265 0000008b T isr_stub_table +002046f0 0000008b T sfs_get_formatted_name +00206390 0000008d T kbd_gets +00207970 0000008d T strdup +00208cc0 0000008e T int_pow +00204660 0000008f T sfs_init +00207610 00000091 T memclr_sse2 +00203eb0 00000091 T ramfs_write_file +00202d40 00000092 T format_83_name +00204e80 00000092 T ide_initialize +00206fe0 00000092 T miner_main +00205f50 00000092 T pci_enumerate +00206d10 00000093 T malloc +00207240 00000097 T test_sse +002011f0 0000009c T create_descriptor +00208510 0000009d T print_uint +002055c0 0000009d T terminal_clearl +00200620 0000009f T get_cpu_vendor_string +002083c0 0000009f T print_hex +002073d0 000000a0 T sse2_memcpy +00207790 000000a1 T strcasecmp +002012c0 000000a2 T exception_dispatcher +00208460 000000a5 T print_double +00200f90 000000a7 T print_all_regs +00205420 000000b2 T terminal_initializec +00205e90 000000b9 T pci_config_read_block +002013f0 000000cd T idt_init +00204da0 000000dc T ide_identify +00203fc0 000000de T ramfs_delete_file +002006c0 000000e8 T get_cpu_brand_string +002040a0 000000ec T ramfs_resolve_path +00208170 000000ee T print_int +00203dc0 000000f0 T ramfs_create_file +002086c0 000000f7 T print_hex64 +00206090 000000f7 T setup_hook +00202de0 000000ff T fat32_list_root +00206ae0 000000ff T pmm_init +00206670 00000102 T append_char +002085b0 0000010d T print_luint +00203900 0000011a T fat32_create_directory +00206190 0000011f T remove_hook +00202bb0 00000128 T fat32_init +00207a00 00000133 T strtok +002093f0 00000136 T __umoddi3 +00204780 00000141 T sfs_create_file +00200460 00000148 T kernel_main +002043a0 0000014b T ssfs_read_file +00201090 00000154 T gdt_install +00207470 00000156 T sse2_strncpy +00208260 00000157 T print_lint +00207f30 0000015f T atof +002044f0 0000016a T ssfs_write_file +00205ab0 0000016a T terminal_get_shifted +00200250 0000018a T begin_anim +00203a20 000001a4 T fat32_change_directory +00204f20 000001a4 T ide_read48 +00204190 000001b8 T ramfs_resolve_fd_dir +00201580 000001ea t duckfs_alloc_file_data +00201c70 000001ee T duckfs_create_dir +002048d0 000001f0 T sfs_read_file +002017d0 000001fb T duckfs_find +0020eb60 00000200 B buffer +0020e8e0 00000200 b sector +002023e0 00000214 T duckfs_truncate +002067d0 00000223 T keyboard_handler +002050d0 00000234 T ide_write48 +002021a0 00000237 T duckfs_write_data +0020ed60 00000240 B func_list +002056e0 00000241 T terminal_putchar +00206420 00000247 T gets_append_char +002028a0 00000288 T duckfs_delete_dir +00203660 00000298 T fat32_create_file +002019d0 000002a0 T duckfs_create_file +00202600 000002a0 T duckfs_delete_file +00202ee0 000002c2 T fat32_read_file +00201ec0 000002d1 T duckfs_append_data +00204ac0 000002db T sfs_write_file +002007b0 0000034a T execute +00200b00 00000448 T kshell_start +002087c0 0000045c T printf +002031b0 000004a5 T fat32_write_file +0020e0a0 00000800 b idt +0020d020 00001000 B vars +00230000 00010000 n stack_bottom +00210000 00020000 b bitmap +00240000 ffff0000 B __kernel_end diff --git a/drivers/audio/pcspeaker.c b/drivers/audio/pcspeaker.c new file mode 100644 index 0000000..55a64a9 --- /dev/null +++ b/drivers/audio/pcspeaker.c @@ -0,0 +1,46 @@ +#include +#include + +#include + +/* +this code is taken from the OSDev wiki: https://wiki.osdev.org/PC_Speaker +with slight modifications to the local variable and parameter names, +along with removing the 'static' keyword from play_sound and nosound (which is renamed to stop_sound) +*/ + +void play_sound(uint32_t nfrequence) +{ + uint32_t div; + uint8_t tmp; + + // Set the PIT to the desired frequency + div = 1193180 / nfrequence; + outb(0x43, 0xb6); + outb(0x42, (uint8_t) (div)); + outb(0x42, (uint8_t) (div >> 8)); + + // And play the sound using the PC speaker + tmp = inb(0x61); + if (tmp != (tmp | 3)) + { + outb(0x61, tmp | 3); + } + } + +// make it shut up +void stop_sound(void) +{ + uint8_t tmp = inb(0x61) & 0xFC; + outb(0x61, tmp); + } + +// Make a beep +void beep(void) +{ + play_sound(1000); + //timer_wait(10); + sleep(10); + stop_sound(); + //set_PIT_2(old_frequency); + } diff --git a/drivers/elf.c b/drivers/elf.c index 7608d4d..3139910 100644 --- a/drivers/elf.c +++ b/drivers/elf.c @@ -13,10 +13,10 @@ elf_executable_t* load_elf32(void* elf_data) { - /*Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data;*/ + Elf32_Ehdr* ehdr = (Elf32_Ehdr*)elf_data; /* Check ELF magic */ - /*if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0) + if (memcmp(ehdr->e_ident, (uint8_t*)("\x7F""ELF"), 4) != 0) { printf("Invalid ELF file\n"); return NULL; @@ -30,7 +30,8 @@ elf_executable_t* load_elf32(void* elf_data) Elf32_Phdr* phdrs = (Elf32_Phdr*)((uint8_t*)elf_data + ehdr->e_phoff); - for (int i = 0; i < ehdr->e_phnum; i++) { + for (int i = 0; i < ehdr->e_phnum; i++) + { Elf32_Phdr* phdr = &phdrs[i]; if (phdr->p_type != PT_LOAD) { @@ -43,7 +44,7 @@ elf_executable_t* load_elf32(void* elf_data) for (uint32_t page = 0; page < segment_pages; page++) { - void* phys = alloc_page(); + void* phys = pmm_alloc_page(); void* virt = (void*)(vaddr_start + page * PAGE_SIZE); map_page(phys, virt); memset(virt, 0, PAGE_SIZE); @@ -53,12 +54,15 @@ elf_executable_t* load_elf32(void* elf_data) void* src = (uint8_t*)elf_data + phdr->p_offset; memcpy(dest, src, phdr->p_filesz); - printf("Mapped segment %d: 0x%08x–0x%08x (memsz: %u, filesz: %u)\n", i, phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, phdr->p_memsz, phdr->p_filesz); +#ifdef _DEBUG + printf("Mapped segment %d: ", i); + printf("0x%x - 0x%x (memsz: %u, filesz: %u)\n", phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, phdr->p_memsz, phdr->p_filesz); +#endif } elf_executable_t* result = malloc(sizeof(elf_executable_t)); - result->entry_point = (void*)(uintptr_t)ehdr->e_entry; - return result;*/ + result->entry_point = (elf_entry_t)(uintptr_t)ehdr->e_entry; + return result; return NULL; } diff --git a/drivers/exec/secf.c b/drivers/exec/secf.c new file mode 100644 index 0000000..e883910 --- /dev/null +++ b/drivers/exec/secf.c @@ -0,0 +1,48 @@ +/* + Simple Executable Code Format + + SECF is a executable format for any platform (though designed with x86(-32) in mind.) + that makes use of registers, syscalls/interrupts, and other tables/structures instead of libraries. + + register map: + (unused means the program can use the register without any issue, no data used/passed by the SECF will be there) + + EAX: unused + EBX: unused + ECX: arg string length + EDX: variable area size (bytes) + ESI: pointer to arg string + EDI: unused + ESP: unused, normal function + EBP: pointer to variable area + + + + The variable area is a area of a specific size (size in EDX) that can be used for storing variables/temporary data. + Any additional memory space needed can be aquired via malloc. + The minimum size of the variable area is 16 bytes and a maximum size of 64KiB. + + + Use syscall/int (number TBT) to call functions +*/ + +#include +#include + +void* init_var_area(size_t size) +{ + if (size == (size_t) 0) + { + return NULL; /* size 0 is invalid. */ + } + else if (size >= 65536) + { + return NULL; /* size above 65,536 is invalid. */ + } + else if (size < 16) + { + size = 16; + } + + return malloc(size); /* No need to check for null because we'd return null in that case */ +} diff --git a/drivers/fs/ekfs.c b/drivers/fs/ekfs.c new file mode 100644 index 0000000..adc0a20 --- /dev/null +++ b/drivers/fs/ekfs.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#include + +/* work on this later */ +#if 0 + +/* note: __l being 0 is allowed, because that way read() can be used to tell if a file exists (with return value 0) */ +int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l) +{ + int rv = 0; + + if (!__f || !__b || (!__f->f_inode)) + { + return -1; + } + + /* we assume drive 0 is already mounted */ + + char buffer[512]; + memset(buffer, 0, 512); + + int num_sectors = __f->f_inode->i_len / 512; + + if ((__l / 512) > num_sectors) + { + return EKFS_E_FILETOOSMALL; + } + + int read_sectors = num_sectors; + + for (int i = 0; i < read_sectors; i++); + { + rv = read_sector(__f->f_inode->i_start, buffer); + + if (rv != 0) + { + break; + } + + + } + + return rv; +} + +#endif diff --git a/drivers/fs/fat16.c b/drivers/fs/fat16.c new file mode 100644 index 0000000..585d059 --- /dev/null +++ b/drivers/fs/fat16.c @@ -0,0 +1,374 @@ +#include +#include +#include + +#include + +/* + READ BELOW!!! + Before any of you (or me,) use this code, please note that the functions below REQUIRE 8.3 formatted names. + in fat16.h there is a helper function for convertion between normal filenames and 8.3 ones. ('filename_to_83', see static implementation in fat16.h) +*/ + +static fat16_fs_t fs; +static uint8_t boot_sector[SECTOR_SIZE]; + +int fat16_mount(uint8_t drive) +{ + if (read_sector(0, boot_sector) != 0) + { + return -1; + } + + fs.bytes_per_sector = boot_sector[11] | (boot_sector[12] << 8); + fs.sectors_per_cluster = boot_sector[13]; + fs.reserved_sector_count = boot_sector[14] | (boot_sector[15] << 8); + fs.num_fats = boot_sector[16]; + fs.root_entry_count = boot_sector[17] | (boot_sector[18] << 8); + fs.total_sectors_16 = boot_sector[19] | (boot_sector[20] << 8); + fs.sectors_per_fat = boot_sector[22] | (boot_sector[23] << 8); + fs.total_sectors = fs.total_sectors_16 != 0 ? fs.total_sectors_16 : boot_sector[32] | (boot_sector[33]<<8) | (boot_sector[34]<<16) | (boot_sector[35]<<24); + fs.fat_start_lba = fs.reserved_sector_count; + fs.root_dir_lba = fs.fat_start_lba + (fs.num_fats * fs.sectors_per_fat); + fs.data_start_lba = fs.root_dir_lba + ((fs.root_entry_count * 32 + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector); + + return 0; +} + +static uint32_t cluster_to_lba(uint16_t cluster) +{ + return fs.data_start_lba + (cluster - 2) * fs.sectors_per_cluster; +} + +/* ----------------------- FAT helpers ------------------------- */ +static int read_fat_entry(uint16_t cluster, uint16_t* out_value) +{ + uint32_t offset = (uint32_t)cluster * 2; + uint32_t sector_index = offset / fs.bytes_per_sector; + uint32_t idx = offset % fs.bytes_per_sector; + uint8_t sector[SECTOR_SIZE]; + + if (read_sector(fs.fat_start_lba + sector_index, sector) != 0) + { + return -1; + } + + if (idx == fs.bytes_per_sector - 1) + { + /* entry spans boundary -> read next sector */ + uint8_t next_sector[SECTOR_SIZE]; + + if (read_sector(fs.fat_start_lba + sector_index + 1, next_sector) != 0) + { + return -1; + } + + *out_value = sector[idx] | (next_sector[0] << 8); + } + else + { + *out_value = sector[idx] | (sector[idx + 1] << 8); + } + return 0; +} + + +static int write_fat_entry(uint16_t cluster, uint16_t value) +{ + uint32_t offset = cluster * 2; + uint32_t sector_lba = fs.fat_start_lba + (offset / fs.bytes_per_sector); + uint8_t sector[SECTOR_SIZE]; + + if (read_sector(sector_lba, sector) != 0) + { + return -1; + } + + sector[offset % fs.bytes_per_sector] = value & 0xFF; + sector[(offset % fs.bytes_per_sector) + 1] = (value >> 8) & 0xFF; + + /* write to all FAT copies */ + for (uint8_t f = 0; f < fs.num_fats; f++) + { + if (write_sector(fs.fat_start_lba + f * fs.sectors_per_fat + (offset / fs.bytes_per_sector), sector) != 0) + { + return -1; + } + } + return 0; +} + +static int find_free_cluster(uint16_t* out_cluster) +{ + uint16_t total_clusters = (fs.total_sectors - fs.data_start_lba) / fs.sectors_per_cluster; + uint16_t value; + for (uint16_t c = 2; c < total_clusters; c++) + { + if (read_fat_entry(c, &value) != 0) + { + return -1; + } + + if (value == 0x0000) + { + *out_cluster = c; + return 0; + } + } + return -1; /* no free cluster */ +} + + +/* -------------------- Root directory ------------------------- */ +static int find_free_root_entry(uint32_t* out_sector, uint32_t* out_offset) +{ + uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector; + uint8_t sector[SECTOR_SIZE]; + + for (uint32_t i = 0; i < root_dir_sectors; i++) + { + if (read_sector(fs.root_dir_lba + i, sector) != 0) + { + return -1; + } + + for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32) + { + if (sector[offset] == 0x00 || sector[offset] == 0xE5) + { + *out_sector = fs.root_dir_lba + i; + *out_offset = offset; + return 0; + } + } + } + return -1; +} + +/* -------------------- File operations ----------------------- */ +int fat16_find_file(const char* name, fat16_file_t* out_file) +{ + uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector; + uint8_t sector[SECTOR_SIZE]; + + for (uint32_t i = 0; i < root_dir_sectors; i++) + { + if (read_sector(fs.root_dir_lba + i, sector) != 0) + { + return -1; + } + + for (uint32_t offset = 0; offset < SECTOR_SIZE; offset += 32) + { + if (sector[offset] == 0x00) + { + return -1; /* no more entries */ + } + else if (sector[offset] == 0xE5) + { + continue; /* deleted entry */ + } + + if (memcmp(sector + offset, name, 11) == 0) + { + memcpy(out_file->name, sector + offset, 12); + out_file->attr = sector[offset + 11]; + out_file->first_cluster = sector[offset + 26] | (sector[offset + 27] << 8); + out_file->size = sector[offset + 28] | (sector[offset + 29] << 8) | (sector[offset + 30] << 16) | (sector[offset + 31] << 24); + + return 0; + } + } + } + return -1; +} + +int fat16_create_file(const char* name, fat16_file_t* out_file) +{ + uint16_t free_cluster; + + if (find_free_cluster(&free_cluster) != 0) + { + return -1; + } + + uint32_t sector_lba, offset; + + if (find_free_root_entry(§or_lba, &offset) != 0) + { + return -1; + } + + uint8_t sector[SECTOR_SIZE]; + + if (read_sector(sector_lba, sector) != 0) + { + return -1; + } + + /* Fill root entry */ + memset(sector + offset, ' ', 11); + memcpy(sector + offset, name, 11); + sector[offset + 11] = 0x20; /* normal file */ + sector[offset + 26] = free_cluster & 0xFF; + sector[offset + 27] = (free_cluster >> 8) & 0xFF; + sector[offset + 28] = 0; sector[offset + 29] = 0; + sector[offset + 30] = 0; sector[offset + 31] = 0; + + if (write_sector(sector_lba, sector) != 0) + { + return -1; + } + + /* mark cluster as end-of-chain */ + if (write_fat_entry(free_cluster, 0xFFFF) != 0) + { + return -1; + } + + if (out_file) + { + memset(out_file, 0, sizeof(fat16_file_t)); + strncpy(out_file->name, name, 11); + out_file->first_cluster = free_cluster; + out_file->size = 0; + out_file->attr = 0x20; + } + + return 0; +} + +int fat16_write_file(fat16_file_t* file, const void* buffer, uint32_t size) { + const uint8_t* buf = (const uint8_t*)buffer; + uint32_t bytes_remaining = size; + uint16_t cluster = file->first_cluster; + + if (cluster == 0) return -1; /* safety: file must have a cluster */ + + while (bytes_remaining > 0) { + uint32_t lba = cluster_to_lba(cluster); + + for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++) { + uint8_t sector[SECTOR_SIZE]; + memset(sector, 0, SECTOR_SIZE); + uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE; + memcpy(sector, buf, copy_bytes); + if (write_sector(lba + i, sector) != 0) return -1; + buf += copy_bytes; + bytes_remaining -= copy_bytes; + } + + uint16_t next_cluster; + if (bytes_remaining > 0) { + if (find_free_cluster(&next_cluster) != 0) return -1; + if (write_fat_entry(cluster, next_cluster) != 0) return -1; + if (write_fat_entry(next_cluster, 0xFFFF) != 0) return -1; + cluster = next_cluster; + } + } + + /* Update file size in root entry (your code already does this on disk) */ + /* Now update the in-memory struct so subsequent reads use the new size */ + file->size = size; + + /* optionally: refresh metadata from disk: + fat16_find_file(file->name, file); */ + + return 0; +} + + +int fat16_read_file(fat16_file_t* file, void* buffer) +{ + uint8_t sector[SECTOR_SIZE]; + uint16_t cluster = file->first_cluster; + uint32_t bytes_remaining = file->size; + uint8_t* buf = (uint8_t*)buffer; + + while (cluster >= 0x0002 && cluster < 0xFFF8) + { + uint32_t lba = cluster_to_lba(cluster); + for (uint8_t i = 0; i < fs.sectors_per_cluster && bytes_remaining > 0; i++) + { + if (read_sector(lba + i, sector) != 0) + { + return -1; + } + uint32_t copy_bytes = bytes_remaining < SECTOR_SIZE ? bytes_remaining : SECTOR_SIZE; + memcpy(buf, sector, copy_bytes); + buf += copy_bytes; + bytes_remaining -= copy_bytes; + } + + /* read next cluster from FAT */ + uint32_t fat_offset = cluster * 2; /* FAT16 */ + uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector); + uint16_t fat_entry; + if (read_sector(fat_sector, sector) != 0) + { + return -1; + } + fat_entry = sector[fat_offset % fs.bytes_per_sector] | (sector[(fat_offset % fs.bytes_per_sector) + 1] << 8); + cluster = fat_entry; + } + + return 0; +} + +int fat16_delete_file(const char* filename) +{ + uint8_t sector[512]; + uint32_t root_dir_sectors = ((fs.root_entry_count * 32) + (fs.bytes_per_sector - 1)) / fs.bytes_per_sector; + uint32_t root_dir_start = fs.root_dir_lba; + + for (uint32_t s = 0; s < root_dir_sectors; s++) + { + if (read_sector(root_dir_start + s, sector) != 0) + return -1; + + for (int i = 0; i < fs.bytes_per_sector; i += 32) + { + uint8_t* entry = §or[i]; + + if (entry[0] == 0x00) + return -1; // end of directory + if (entry[0] == 0xE5) + continue; // already deleted + + if (memcmp(entry, filename, 11) == 0) + { + // Found the file — mark as deleted + entry[0] = 0xE5; + + if (write_sector(root_dir_start + s, sector) != 0) + return -1; + + // Free FAT chain + uint16_t cluster = entry[26] | (entry[27] << 8); + while (cluster >= 0x0002 && cluster < 0xFFF8) + { + uint32_t fat_offset = cluster * 2; + uint32_t fat_sector = fs.fat_start_lba + (fat_offset / fs.bytes_per_sector); + uint32_t ent_offset = fat_offset % fs.bytes_per_sector; + + if (read_sector(fat_sector, sector) != 0) + break; + + uint16_t next_cluster = sector[ent_offset] | (sector[ent_offset + 1] << 8); + sector[ent_offset] = 0x00; + sector[ent_offset + 1] = 0x00; + + if (write_sector(fat_sector, sector) != 0) + break; + + cluster = next_cluster; + } + + return 0; // success + } + } + } + + return -1; // file not found +} + diff --git a/drivers/fs/vfs.c b/drivers/fs/vfs.c index 3ab5a12..d10d29d 100644 --- a/drivers/fs/vfs.c +++ b/drivers/fs/vfs.c @@ -1,24 +1,76 @@ #include #include +#include #include +/* we use something similar to the Linux kernel in terms of a VFS system */ -typedef struct vfs_file_header { - char* filename; /* The filename, not the path. */ - - int32_t fd; - - uint8_t type_info; /* Bits 0 - 3 -> File type, Bits 4 - 7 FS type */ - - uint16_t* fs_header; - - struct vfs_file_header* next; /* Linked list */ -} vfs_file_header_t; +#define MAX_FDS 64 + +struct inode { + size_t size; + int permissions; + void *fs_data; /* FS-specific */ +}; + +struct file_ops { + int (*read)(struct file*, char*, size_t); + int (*write)(struct file*, const char*, size_t); +}; + +struct file { + struct inode* f_inode; + size_t f_offset; + size_t f_refcount; + const struct file_ops f_ops; +}; -vfs_file_header_t* root; + +struct fdtable { + struct file* fds[MAX_FDS]; +}; + + + +int vfs_handle_stdout(struct file* __f, const char* __s, size_t __l) +{ + (void) __f; + terminal_write(__s, __l); + + return 0; +} + +struct fdtable* vfs_init_kernel_fdtable(void) +{ +#if 0 + struct fdtable* ft = malloc(sizeof(struct fdtable)); + struct file* _stdout = malloc(sizeof(struct file)); + struct file* _stdin = malloc(sizeof(struct file)); + + if (!ft || !_stdin || !_stdout) + { + return NULL; + } + + _stdout->f_inode = NULL; + _stdout->f_offset = 0; + _stdout->f_refcount = 1; + _stdout->f_ops = { .read = NULL, .write = vfs_handle_stdout }; +#endif + return NULL; +} + +int init_vfs(int argc, char** argv) +{ + (void) argc; + (void) argv; + + return 0; +} + /* @@ -28,5 +80,7 @@ vfs_file_header_t* root; wow. and now my CPU fan is going nuts. - --update: now it works. I had to go back to nouveau instead of the proprietary nVidia drivers.. + --update: now it works. I had to go back to nouveau instead of the proprietary nVidia®©™ drivers.. + + --update: I wrote what months ago. now is 3/12/2026, I don't even remember what was going on well. wow. */ diff --git a/drivers/gdt.c b/drivers/gdt.c index 78e0974..b93f50d 100644 --- a/drivers/gdt.c +++ b/drivers/gdt.c @@ -7,8 +7,8 @@ uint64_t gdt[GDT_ENTRIES]; struct { - uint16_t limit; - uint32_t base; + uint16_t limit; + uint32_t base; } __attribute__((packed)) gp; diff --git a/drivers/idt.c b/drivers/idt.c index 74c0ad4..03ce189 100644 --- a/drivers/idt.c +++ b/drivers/idt.c @@ -1,6 +1,11 @@ #include #include +#include +#include + +#include + #include @@ -29,8 +34,7 @@ typedef struct { } __attribute__((packed)) idtr_t; __attribute__((aligned(0x10))) - -static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance +static idt_entry_t idt[256]; /* create an array of IDT entries; aligned for performance */ static idtr_t idtr; @@ -38,91 +42,6 @@ static bool vectors[IDT_MAX_DESCRIPTORS]; extern void* isr_stub_table[]; - -__attribute__((noreturn)) -void exception_dispatcher(uint32_t int_no, uint32_t err_code) -{ - switch (int_no) - { - case 0: - printf("Divide by zero exception\n"); - break; - case 13: - printf("General Protection Fault: err=0x%x\n", err_code); - break; - case 14: - { - uint32_t cr2; - asm volatile ("mov %%cr2, %0" : "=r"(cr2)); - printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code); - break; - } - default: - printf("Unhandled exception #%u, err=0x%x\n", int_no, err_code); - break; - } - - uint16_t cs, ds, es, ss; - asm volatile ("mov %%cs, %0" : "=r"(cs)); - asm volatile ("mov %%ds, %0" : "=r"(ds)); - asm volatile ("mov %%es, %0" : "=r"(es)); - asm volatile ("mov %%ss, %0" : "=r"(ss)); - - printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss); - - asm volatile ("cli; hlt"); - - /* Will never be reached */ - while (true) - { - asm volatile ("hlt" ::: "memory"); - } -} - - - -void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) -{ - idt_entry_t* descriptor = &idt[vector]; - - descriptor->isr_low = (uint32_t)isr & 0xFFFF; - descriptor->kernel_cs = 0x08; - descriptor->attributes = flags; - descriptor->isr_high = (uint32_t)isr >> 16; - descriptor->reserved = 0; -} - -void pic_remap(void) -{ - uint8_t a1, a2; - - /* Save masks */ - a1 = inb(PIC1_DATA); - a2 = inb(PIC2_DATA); - - /* Start initialization sequence (in cascade mode) */ - outb(PIC1_COMMAND, 0x11); - outb(PIC2_COMMAND, 0x11); - - /* Set vector offset */ - outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */ - outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */ - - /* Tell Master PIC about Slave PIC at IRQ2 (0000 0100) */ - outb(PIC1_DATA, 0x04); - - /* Tell Slave PIC its cascade identity (0000 0010) */ - outb(PIC2_DATA, 0x02); - - /* Set 8086/88 mode */ - outb(PIC1_DATA, 0x01); - outb(PIC2_DATA, 0x01); - - /* Restore saved masks */ - outb(PIC1_DATA, a1); - outb(PIC2_DATA, a2); -} - void idt_init(void) { idtr.base = (uintptr_t)&idt[0]; @@ -136,13 +55,141 @@ void idt_init(void) extern void* irq_stub_table[]; - for (uint8_t i = 0; i < 16; i++) + for (uint8_t i = 0; i < 20; i++) { idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E); } asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */ - asm volatile ("sti"); /* set the interrupt flag */ + //asm volatile ("sti"); /* set the interrupt flag */ } +registers_t* interrupt_dispatcher(registers_t* regs) +{ + if (regs->int_no < 32) + { + printf("external: %s, IDT/GDT: %s, ", ((regs->err_code & 0x0001) ? "true" : "false"), (regs->err_code & 0x0006) ? "IDT" : "GDT"); + printf("LDT: %s, selector: %x (%i)\n", ((regs->err_code & 0x0006) == 0b10) ? "true" : "false", regs->err_code & 0xFFF8, regs->err_code & 0xFFF8); + printf("int: %i (%x), err: %i (%x)\n", regs->int_no, regs->int_no, regs->err_code, regs->err_code); + exception_handler(regs); + } + else if (regs->int_no < 52) + { + uint32_t irq = regs->int_no - 32; + + regs = irq_handler(irq, regs); + + if (irq >= 8) + { + outb(0xA0, 0x20); /* acknowledge the IRQ to slave PIC */ + } + + outb(0x20, 0x20); /* acknowledge the IRQ to master PIC */ + } + + return regs; +} + +__noreturn +void exception_handler(registers_t* regs) +{ + uint32_t int_no = regs->int_no; + uint32_t err_code = regs->err_code; + + switch (int_no) + { + case 0: + printf("Divide by zero exception (or other division error)\n"); + break; + case 2: + printf("NMI encountered\n"); + break; + case 6: /* XXX: NOTE: this can be used to emulate instructions that do not exist on the current CPU :NOTE :XXX */ + printf("Invalid opcode encountered at %p\n", regs->eip); + break; + case 7: /* XXX: NOTE: use this for FPU emulation and for saving/restoring FPU registers in a multiprocessing enviroment :NOTE :XXX */ + printf("FPU instructions used, but FPU is nonexistant/disabled\n"); + break; + case 8: /* double fault */ + printf("Double fault at %p, err %i\n", regs->eip, regs->err_code); + break; + case 13: + printf("General Protection Fault: err=0x%x at %p\n", err_code, regs->eip); + break; + case 14: + { + uint32_t cr2; + asm volatile ("mov %%cr2, %0" : "=r"(cr2)); + printf("PF addr=%p eip=%p err=%x\n", cr2, regs->eip, err_code); + //printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code); + break; + } + default: + printf("Unhandled exception #%u, err=0x%x at %p\n", int_no, err_code, regs->eip); + break; + } + + uint16_t cs, ds, es, ss; + asm volatile ("mov %%cs, %0" : "=r"(cs)); + asm volatile ("mov %%ds, %0" : "=r"(ds)); + asm volatile ("mov %%es, %0" : "=r"(es)); + asm volatile ("mov %%ss, %0" : "=r"(ss)); + + if (((uint16_t) regs->cs != cs) || ((uint16_t) regs->ds != ds) || ((uint16_t) regs->es != es)) + { + printf("segment register mismatch!\n"); + } + + printf("cs: 0x%x, ds: 0x%x, es: 0x%x,\nss: 0x%x, fs: 0x%x, gs: 0x%x\n", regs->cs, regs->ds, regs->es, ss, regs->fs, regs->gs); + + asm volatile ("cli; hlt"); + + /* Will never be reached */ + while (true) + { + asm volatile ("hlt" ::: "memory"); + } +} + +void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) +{ + idt_entry_t* descriptor = &idt[vector]; + + descriptor->isr_low = (uint32_t) isr & 0xFFFF; + descriptor->kernel_cs = 0x08; + descriptor->attributes = flags; + descriptor->isr_high = (uint32_t) isr >> 16; + descriptor->reserved = 0; +} + +void pic_remap(void) +{ + uint8_t a1, a2; + + /* save masks */ + a1 = inb(PIC1_DATA); + a2 = inb(PIC2_DATA); + + /* start initialization sequence (in cascade mode) */ + outb(PIC1_COMMAND, 0x11); + outb(PIC2_COMMAND, 0x11); + + /* set vector offset */ + outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */ + outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */ + + /* tell the master PIC about Slave PIC at IRQ2 (0000 0100) */ + outb(PIC1_DATA, 0x04); + + /* tell the slave PIC its cascade identity (0000 0010) */ + outb(PIC2_DATA, 0x02); + + /* set 8086/88 mode */ + outb(PIC1_DATA, 0x01); + outb(PIC2_DATA, 0x01); + + /* restore saved masks */ + outb(PIC1_DATA, a1); + outb(PIC2_DATA, a2); +} diff --git a/drivers/irq.c b/drivers/irq.c index 0d065b6..733cea8 100644 --- a/drivers/irq.c +++ b/drivers/irq.c @@ -3,46 +3,74 @@ #include #include +/* TEMP DEBUG */ +#include + +#include + #include -#define NUM_IRQS 0x90 - -irq_func_t func_list[NUM_IRQS]; +#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */ +typedef struct { + uint32_t irq_no; + irq_func_t func; +} irq_handler_t; -static volatile uint32_t num_irqs_missed = 0; +uint32_t num_irq_handlers = 0; +irq_handler_t handler_list[MAX_IRQ_HANDLERS]; + +volatile uint32_t num_irqs_missed = 0; void irq_init(void) { - for (int i = 0; i < NUM_IRQS; i++) + for (int i = 0; i < MAX_IRQ_HANDLERS; i++) { - func_list[i] = 0x0; + handler_list[i].irq_no = 0; + handler_list[i].func = NULL; } - set_irq_handler(0, (irq_func_t*) pit_handler); - set_irq_handler(1, (irq_func_t*) keyboard_handler); + set_irq_handler(0, (irq_func_t) pit_handler); + //set_irq_handler(1, (irq_func_t) ps2_keyboard_handler); } -void irq_handler(uint8_t irq_number) +registers_t* irq_handler(uint32_t irq, registers_t* regs) { - if (irq_number < NUM_IRQS) - { - if (func_list[irq_number]) + uint8_t funcs_called = 0; + + if (num_irq_handlers > 0) + { + for (unsigned int i = 0; i < MAX_IRQ_HANDLERS; i++) { - func_list[irq_number](); - outb(0x20, 0x20); /* Acknowledge the IRQ to PIC */ - } - else - { - num_irqs_missed++; + if (handler_list[i].irq_no == irq && handler_list[i].func != NULL) + { + regs = handler_list[i].func(regs); + funcs_called++; + /* PIC IRQ acknowledgement happens in idt.c */ + } } } + + if (funcs_called == 0) + { + num_irqs_missed++; + } + + return regs; } -void set_irq_handler(uint32_t num, irq_func_t* handler) +uint32_t get_interrupts_missed(void) { - if (num < NUM_IRQS) + return num_irqs_missed; +} + +void set_irq_handler(uint32_t num, irq_func_t handler) +{ + if (num < MAX_IRQ_HANDLERS) { - func_list[num] = (irq_func_t)handler; + handler_list[num].irq_no = num; + handler_list[num].func = handler; + + num_irq_handlers++; } } diff --git a/drivers/keyboard.c b/drivers/keyboard.c new file mode 100644 index 0000000..3dddd12 --- /dev/null +++ b/drivers/keyboard.c @@ -0,0 +1,148 @@ +#include +#include +#include +#include + +#include + +#include + +/* + PS/2 Controller IO Ports + + The PS/2 Controller itself uses 2 IO ports (IO ports 0x60 and 0x64). Like many IO ports, reads and writes may access different internal registers. + + Historical note: The PC-XT PPI had used port 0x61 to reset the keyboard interrupt request signal (among other unrelated functions). Port 0x61 has no keyboard related functions on AT and PS/2 compatibles. + IO Port Access Type Purpose + 0x60 Read/Write Data Port + 0x64 Read Status Register + 0x64 Write Command Register +*/ + +#define PS2_DATA_PORT 0x60 +#define PS2_STATUS_PORT 0x64 + +#define KEYBOARD_IRQ 1 + +static const char scancode_map[128] = { + 0, 27, '1','2','3','4','5','6','7','8','9','0','-','=','\b', /* Backspace */ + '\t', /* Tab */ + 'q','w','e','r','t','y','u','i','o','p','[',']','\n', /* Enter */ + 0, /* Control */ + 'a','s','d','f','g','h','j','k','l',';','\'','`', + 0, /* Left shift */ + '\\','z','x','c','v','b','n','m',',','.','/', + 0, /* Right shift */ + '*', + 0, /* Alt */ + ' ', /* Spacebar */ + 0, /* Caps lock */ + /* The rest are function and control keys */ +}; + +volatile uint32_t mods = 0; +volatile bool keyboard_initialied = false; +volatile bool extended = false; + +int init_keyboard(void) +{ +#ifdef _DEBUG + printf("Initializing the keyboard...\n"); +#endif + + keyboard_initialied = true; + + set_irq_handler(1, (irq_func_t) keyboard_handler); + +#ifdef _DEBUG + printf("Keyboard initialized\n"); +#endif + + return 0; +} + + +registers_t* keyboard_handler(registers_t* regs) +{ + if (!(inb(PS2_STATUS_PORT) & 1)) + { + return regs; + } + + uint8_t scancode = inb(PS2_DATA_PORT); + + if (scancode & 0x80) + { + return regs; + } + + /* Handle shift press/release */ + if (scancode == 0x2A || scancode == 0x36) + { + mods |= MODIFIER_SHIFT; + return regs; + } + else if (scancode == 0xAA || scancode == 0xB6) + { + mods &= MODIFIER_SHIFT_DESTROY; + return regs; + } + else if (scancode == 0x3A) + { + TOGGLE_BIT(mods, 0); /* TOGGLE_BIT defined in types.h, should move elsewhere. */ + return regs; + } + /*else if (scancode == 0xE0) + { + extended = true; + return; + }*/ + /* XXX: NOTE: we don't do extended codes yet. :NOTE :XXX */ + /*if (extended) + {*/ + /*switch (scancode) + { + case 0x48: + c = KEY_ARROW_UP; + break; + case 0x50: + c = KEY_ARROW_DOWN; + break; + case 0x4B: + c = KEY_ARROW_LEFT; + break; + case 0x4D: + c = KEY_ARROW_RIGHT; + break; + default: + c = KEY_NONE; + break; + }*/ + + + /*tty_receive_char(c, mod); + + extended = false; + + return; + }*/ + + bool release = scancode & 0x80; + scancode &= 0x7F; + + if (release) + { + return regs; + } + + uint16_t c = (uint16_t) scancode_map[scancode]; + + if (c) + { + //tty_receive_char(c, mods); + char ch = tty_translate_char(c, mods); + tty_input_char(tty_get_active(), ch); + } + + return regs; +} diff --git a/drivers/new_tty.c b/drivers/new_tty.c new file mode 100644 index 0000000..8a3c266 --- /dev/null +++ b/drivers/new_tty.c @@ -0,0 +1,382 @@ +#include +#include +#include +#include + +#include + +#include + + + +static tty_t ttys[MAX_TTYS]; +static uint8_t num_ttys = 0; +static tty_t* active_tty = NULL; + +static inline size_t next_index(size_t index) +{ + return (index + 1) % TTY_BUFFER_SIZE; +} + +static inline bool tty_empty(tty_t* tty) +{ + return tty->head == tty->tail; +} + +static inline bool tty_full(tty_t* tty) +{ + return ((tty->head + 1) % TTY_BUFFER_SIZE) == tty->tail; +} + +static inline bool is_canonical(tty_t* tty) +{ + return (tty->flags & TTY_CANONICAL) != 0; +} + +tty_t* tty_get_active(void) +{ + return active_tty; +} + +void tty_backspace(tty_t* tty) +{ + if (tty->head == tty->tail) + { + return; /* buffer empty */ + } + //tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE; + tty->head = (tty->head + TTY_BUFFER_SIZE - 1) / TTY_BUFFER_SIZE; +} + +ssize_t tty_read_active(char* buf, size_t count) +{ + return tty_read(active_tty, buf, count); +} + +/*ssize_t tty_read(tty_t* tty, char* buf, size_t count) +{ + size_t bytes_read = 0; + + while (bytes_read < count) + { + IRQ_DISABLE(); + spin_lock(&tty->lock); + + if (!tty_empty(tty)) + { + char c = tty->input_buffer[tty->tail]; + tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE; + tty->tail = next_index(tty->tail); + + spin_unlock(&tty->lock); + IRQ_ENABLE(); /* change? *//* + + buf[bytes_read++] = c; + + if (is_canonical(tty) && c == '\n') + { + break; + } + } + else + { + spin_unlock(&tty->lock); + IRQ_ENABLE(); + } + } + + return bytes_read; +}*/ + +ssize_t tty_read(tty_t* tty, char* buf, size_t count) +{ + if (!tty || !buf) + return -1; + + size_t bytes = 0; + + while (1) + { + IRQ_DISABLE(); + spin_lock(&tty->lock); + + if (!tty->line_ready) + { + spin_unlock(&tty->lock); + IRQ_ENABLE(); + continue; /* spin until newline */ + } + + while (bytes < count && tty->tail != tty->head) + { + char c = tty->input_buffer[tty->tail]; + tty->tail = (tty->tail + 1) % TTY_BUFFER_SIZE; + + buf[bytes++] = c; + + if (c == '\n') + { + tty->line_ready = false; + break; + } + } + + spin_unlock(&tty->lock); + IRQ_ENABLE(); + + break; + } + + return bytes; +} + +int input_buffer_put(tty_t* tty, char c) +{ + IRQ_DISABLE(); + spin_lock(&tty->lock); + + size_t next = next_index(tty->head); + + if (next == tty->tail) + { + spin_unlock(&tty->lock); + IRQ_ENABLE(); + return -1; + } + + tty->input_buffer[tty->head] = c; + tty->head = next; + + spin_unlock(&tty->lock); + IRQ_ENABLE(); + + return 0; +} + +int init_tty(void) +{ + if (num_ttys >= MAX_TTYS) + { + return -1; + } + + tty_t* t = &ttys[0]; + + memset(t, 0, sizeof(tty_t)); + + t->flags = TTY_NORMAL; + + active_tty = t; + num_ttys = 1; + + return 0; +} + +tty_t* get_active_tty(void) +{ + return active_tty; +} + +tty_t* make_tty(uint32_t flags) +{ + if (num_ttys >= MAX_TTYS) + { + return NULL; + } + + tty_t* t = &ttys[num_ttys]; + + memset(t, 0, sizeof(tty_t)); + t->flags = flags; + + num_ttys++; + + return t; +} + +void tty_receive_char(char c, uint32_t kbd_mod) +{ + if (!active_tty || c == 0) + { + return; + } + + c = tty_translate_char(c, kbd_mod); + + /* Handle backspace */ + if (c == '\b') + { + tty_backspace(active_tty); + + if (active_tty->head == active_tty->tail) + { + extern void terminal_putcharat(char c, uint16_t row, uint16_t column); + terminal_putcharat('Z', 20, 20); + } + + if (active_tty->flags & TTY_ECHO) + { + /* erase character visually */ + putc('\b'); + } + + return; + } + + input_buffer_put(active_tty, c); + + if (active_tty->flags & TTY_ECHO) + { + if ((active_tty->flags & TTY_PASSWORD) == 0) + { + putc(c); + } + else + { + putc('*'); + } + } +} + +void tty_input_char(tty_t* tty, char c) +{ + if (!tty || c == 0) + return; + + IRQ_DISABLE(); + spin_lock(&tty->lock); + + /* backspace */ + if (c == '\b') + { + if (tty->head != tty->tail) + { + tty->head = (tty->head + TTY_BUFFER_SIZE - 1) % TTY_BUFFER_SIZE; + + if (tty->flags & TTY_ECHO) + { + putc('\b');/* + putc(' '); + putc('\b');*/ + } + } + + spin_unlock(&tty->lock); + IRQ_ENABLE(); + return; + } + + size_t next = (tty->head + 1) % TTY_BUFFER_SIZE; + + if (next != tty->tail) + { + tty->input_buffer[tty->head] = c; + tty->head = next; + + if (c == '\n') + { + tty->line_ready = true; + } + } + + spin_unlock(&tty->lock); + IRQ_ENABLE(); + + if (tty->flags & TTY_ECHO) + { + putc(c); + } +} + +char tty_translate_char(char c, uint32_t modifiers) +{ + bool caps = (modifiers & MODIFIER_CAPS) != 0; + bool shift = (modifiers & MODIFIER_SHIFT) != 0; + bool ctrl = (modifiers & (MODIFIER_LCTRL | MODIFIER_RCTRL)) != 0; + + /* handle alphabetic characters */ + if (c >= 'a' && c <= 'z') + { + if (caps ^ shift) /* XOR logic */ + { + return c - 32; /* to uppercase */ + } + + return c; + } + + if (c >= 'A' && c <= 'Z') + { + if (caps ^ shift) + { + return c; + } + + return c + 32; /* to lowercase */ + } + + /* handle ctrl (should later include control mapping/sending messages to processes via these) */ + if (ctrl) + { + if (c >= 'a' && c <= 'z') + { + return c - 'a' + 1; /* Ctrl+A → 1 */ + } + if (c >= 'A' && c <= 'Z') + { + return c - 'A' + 1; + } + } + + /* shifted symbols (US layout) */ + if (shift) + { + switch (c) + { + case '1': + return '!'; + case '2': + return '@'; + case '3': + return '#'; + case '4': + return '$'; + case '5': + return '%'; + case '6': + return '^'; + case '7': + return '&'; + case '8': + return '*'; + case '9': + return '('; + case '0': + return ')'; + case '-': + return '_'; + case '=': + return '+'; + case '[': + return '{'; + case ']': + return '}'; + case ';': + return ':'; + case '\'': + return '"'; + case ',': + return '<'; + case '.': + return '>'; + case '/': + return '?'; + case '\\': + return '|'; + case '`': + return '~'; + } + } + + return c; +} diff --git a/drivers/pit.c b/drivers/pit.c index bb408fe..ca9dedc 100644 --- a/drivers/pit.c +++ b/drivers/pit.c @@ -2,6 +2,8 @@ #include #include +#include + #include @@ -14,12 +16,14 @@ volatile uint64_t pit_ticks = 0; bool pit_initialized = false; void pit_init(void) -{ +{ + printf("pit_initialized addr = %x\n", &pit_initialized); + #ifdef _DEBUG printf("[ PIT ] Initializing the PIT...\n"); #endif - uint16_t divisor = (uint16_t)1193; + uint16_t divisor = (uint16_t) 1193; /* Send command byte */ outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */ @@ -35,9 +39,10 @@ void pit_init(void) #endif } -void pit_handler(void) +registers_t* pit_handler(registers_t* regs) { pit_ticks++; + return regs; } void pit_sleep(uint64_t ms) @@ -48,3 +53,14 @@ void pit_sleep(uint64_t ms) asm volatile ("hlt"); } } + +/*void pit_sleep(uint64_t ms) +{ + extern task_t* current_task; + + current_task->wakeup_tick = pit_ticks + ms; + current_task->state = TASK_SLEEPING; + + asm volatile("int $32");*/ /* force reschedule immediately */ +/*} +*/ diff --git a/drivers/ps2_keyboard.c b/drivers/ps2_keyboard.c index 323dcc6..2433937 100644 --- a/drivers/ps2_keyboard.c +++ b/drivers/ps2_keyboard.c @@ -3,6 +3,8 @@ #include #include +#include + #include @@ -62,6 +64,8 @@ volatile int32_t current_length = 0; volatile int32_t capacity = 0; volatile uint16_t current_key; +volatile bool use_new_tty = false; + volatile ps2_hook_t* hooks = NULL; volatile int hook_count = 0; @@ -84,6 +88,10 @@ static const char scancode_map[128] = { /* The rest are function and control keys */ }; +void set_use_new_tty(bool t) +{ + use_new_tty = t; +} void keyboard_init(void) { @@ -94,6 +102,8 @@ void keyboard_init(void) outb(0x64, 0xAE); /* Enable keyboard interface (often optional, but here for safety) */ hooks = NULL; + + set_use_new_tty(true); ps2keyboard_initialized = true; @@ -199,6 +209,7 @@ void call_hooks(char c) if (hook_count == 0) { + _sti_asm(); return; } @@ -396,32 +407,45 @@ void free_current_string(void) } } -void keyboard_handler(void) + +registers_t* ps2_keyboard_handler(registers_t* regs) { +#if 0 uint8_t scancode = inb(PS2_DATA_PORT); /* Handle shift press/release */ if (scancode == 0x2A || scancode == 0x36) { shift_pressed = true; - return; + return regs; } else if (scancode == 0xAA || scancode == 0xB6) { shift_pressed = false; - return; + return regs; } else if (scancode == 0x3A) { capslock_pressed = !capslock_pressed; - return; + return regs; } else if (scancode == 0xE0) { extended = true; - return; + return regs; } + uint32_t flags = 0; + + if (capslock_pressed) + { + flags |= MODIFIER_CAPS; + } + + if (shift_pressed) + { + flags |= MODIFIER_SHIFT; + } if (scancode & 0x80) { @@ -430,84 +454,94 @@ void keyboard_handler(void) else { uint16_t c = (uint16_t) scancode_map[scancode]; - if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z')) + + if (!use_new_tty) { - c -= 32; /* Convert to uppercase */ + if ((shift_pressed ^ capslock_pressed) && ((char) c >= 'a') && ((char) c <= 'z')) + { + c -= 32; /* Convert to uppercase */ + } + else if (shift_pressed) + { + c = (uint16_t) terminal_get_shifted((unsigned char) c); + } + + if (extended) + { + switch (scancode) + { + case 0x48: + c = KEY_ARROW_UP; + break; + case 0x50: + c = KEY_ARROW_DOWN; + break; + case 0x4B: + c = KEY_ARROW_LEFT; + break; + case 0x4D: + c = KEY_ARROW_RIGHT; + break; + default: + c = KEY_NONE; + break; + } + + if (gets_called) + { + gets_append_char(c); + + return regs; + } + + current_key = c; + + is_new_key = true; + extended = false; + + return regs; + } + + if (gets_called) + { + gets_append_char(c); + + return regs; + } + + if (c) + { + if (c != '\n') + { + append_char(c); + } + + current_char = c; + is_new_char = true; + + if (c == '\n') + { + /*append_char(c); + current_char = c; + is_new_char = true;*/ + + free_current_string(); + } + } } - else if (shift_pressed) + else { - c = (uint16_t) terminal_get_shifted((unsigned char) c); + tty_receive_char(c, flags); } if (hook_count > 0) { call_hooks(c); } - - if (extended) - { - switch (scancode) - { - case 0x48: - c = KEY_ARROW_UP; - break; - case 0x50: - c = KEY_ARROW_DOWN; - break; - case 0x4B: - c = KEY_ARROW_LEFT; - break; - case 0x4D: - c = KEY_ARROW_RIGHT; - break; - default: - c = KEY_NONE; - break; - } - - if (gets_called) - { - gets_append_char(c); - - return; - } - - current_key = c; - - is_new_key = true; - extended = false; - - return; - } - - if (gets_called) - { - gets_append_char(c); - - return; - } - - if (c) - { - if (c != '\n') - { - append_char(c); - } - - current_char = c; - is_new_char = true; - - if (c == '\n') - { - /*append_char(c); - current_char = c; - is_new_char = true;*/ - - free_current_string(); - } - } - } +#endif + + return regs; } diff --git a/drivers/tty.c b/drivers/tty.c index b6c731a..eb7c712 100644 --- a/drivers/tty.c +++ b/drivers/tty.c @@ -306,3 +306,12 @@ void terminal_update_cursor(void) outb(0x3D5, (uint8_t) ((pos >> 8) & 0xFF)); } +void terminal_putcharat(char c, uint16_t row, uint16_t column) +{ + int _r; + int _c; + terminal_get_cursor(&_r, &_c); + terminal_set_cursor(row, column); + terminal_putchar(c); + terminal_set_cursor((uint16_t) _r, (uint16_t) _c); +} diff --git a/files/idt.c b/files/idt.c new file mode 100644 index 0000000..4faeb2d --- /dev/null +++ b/files/idt.c @@ -0,0 +1,177 @@ +#include +#include +#include + +#include + + +#define IDT_MAX_DESCRIPTORS 256 + +#define PIC1_COMMAND 0x20 +#define PIC1_DATA 0x21 +#define PIC2_COMMAND 0xA0 +#define PIC2_DATA 0xA1 + +/* + Most of the code is this file (and idt.h) are taken from the osdev wiki: https://wiki.osdev.org/Interrupts_Tutorial, though not all of it. +*/ + +typedef struct { + uint16_t isr_low; // The lower 16 bits of the ISR's address + uint16_t kernel_cs; // The GDT segment selector that the CPU will load into CS before calling the ISR + uint8_t reserved; // Set to zero + uint8_t attributes; // Type and attributes; see the IDT page + uint16_t isr_high; // The higher 16 bits of the ISR's address +} __attribute__((packed)) idt_entry_t; + +typedef struct { + uint16_t limit; + uint32_t base; +} __attribute__((packed)) idtr_t; + +__attribute__((aligned(0x10))) + +static idt_entry_t idt[256]; // Create an array of IDT entries; aligned for performance + +static idtr_t idtr; + +static bool vectors[IDT_MAX_DESCRIPTORS]; + +extern void* isr_stub_table[]; + +void idt_init(void) +{ + idtr.base = (uintptr_t)&idt[0]; + idtr.limit = (uint16_t)sizeof(idt_entry_t) * IDT_MAX_DESCRIPTORS - 1; + + for (uint8_t vector = 0; vector < 32; vector++) + { + idt_set_descriptor(vector, isr_stub_table[vector], 0x8E); + vectors[vector] = true; + } + + extern void* irq_stub_table[]; + + for (uint8_t i = 0; i < 16; i++) + { + idt_set_descriptor(32 + i, irq_stub_table[i], 0x8E); + } + + + asm volatile ("lidt %0" : : "m"(idtr)); /* load the new IDT */ + asm volatile ("sti"); /* set the interrupt flag */ +} + +void interrupt_dispatcher(registers_t* regs) +{ + if (regs->int_no < 32) + { + exception_handler(regs); + } + else if (regs->int_no < 48) + { + uint32_t irq = regs->int_no - 32; + irq_handler(irq, regs); + + if (irq >= 8) + { + outb(0xA0, 0x20); /* acknowledge the IRQ to slave PIC */ + } + + outb(0x20, 0x20); /* acknowledge the IRQ to master PIC */ + } +} + +__noreturn +void exception_handler(registers_t* regs) +{ + uint32_t int_no = regs->int_no; + uint32_t err_code = regs->err_code; + + switch (int_no) + { + case 0: + printf("Divide by zero exception (or other division error)\n"); + break; + case 2: + printf("NMI encountered\n"); + break; + case 6: /* XXX: NOTE: this can be used to emulate instructions that do not exist on the current CPU :NOTE :XXX */ + printf("Invalid opcode encountered\n"); + break; + case 7: /* XXX: NOTE: use this for FPU emulation and for saving/restoring FPU registers in a multiprocessing enviroment :NOTE :XXX */ + printf("FPU instructions used, but FPU is nonexistant/disabled\n"); + break; + case 13: + printf("General Protection Fault: err=0x%x at %p\n", err_code, regs->eip); + break; + case 14: + { + uint32_t cr2; + asm volatile ("mov %%cr2, %0" : "=r"(cr2)); + printf("Page Fault at address: 0x%x, err=0x%x\n", cr2, err_code); + break; + } + default: + printf("Unhandled exception #%u, err=0x%x at %p\n", int_no, err_code, regs->eip); + break; + } + + uint16_t cs, ds, es, ss; + asm volatile ("mov %%cs, %0" : "=r"(cs)); + asm volatile ("mov %%ds, %0" : "=r"(ds)); + asm volatile ("mov %%es, %0" : "=r"(es)); + asm volatile ("mov %%ss, %0" : "=r"(ss)); + + printf("CS=0x%04x DS=0x%04x ES=0x%04x SS=0x%04x\n", cs, ds, es, ss); + + asm volatile ("cli; hlt"); + + /* Will never be reached */ + while (true) + { + asm volatile ("hlt" ::: "memory"); + } +} + +void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags) +{ + idt_entry_t* descriptor = &idt[vector]; + + descriptor->isr_low = (uint32_t) isr & 0xFFFF; + descriptor->kernel_cs = 0x08; + descriptor->attributes = flags; + descriptor->isr_high = (uint32_t) isr >> 16; + descriptor->reserved = 0; +} + +void pic_remap(void) +{ + uint8_t a1, a2; + + /* save masks */ + a1 = inb(PIC1_DATA); + a2 = inb(PIC2_DATA); + + /* start initialization sequence (in cascade mode) */ + outb(PIC1_COMMAND, 0x11); + outb(PIC2_COMMAND, 0x11); + + /* set vector offset */ + outb(PIC1_DATA, 0x20); /* IRQs 0-7 mapped to IDT entries 0x20-0x27 (32–39) */ + outb(PIC2_DATA, 0x28); /* IRQs 8-15 mapped to IDT entries 0x28-0x2F (40–47) */ + + /* tell the master PIC about Slave PIC at IRQ2 (0000 0100) */ + outb(PIC1_DATA, 0x04); + + /* tell the slave PIC its cascade identity (0000 0010) */ + outb(PIC2_DATA, 0x02); + + /* set 8086/88 mode */ + outb(PIC1_DATA, 0x01); + outb(PIC2_DATA, 0x01); + + /* restore saved masks */ + outb(PIC1_DATA, a1); + outb(PIC2_DATA, a2); +} diff --git a/files/idt.h b/files/idt.h new file mode 100644 index 0000000..4fe1493 --- /dev/null +++ b/files/idt.h @@ -0,0 +1,18 @@ +#ifndef _IDT_H +#define _IDT_H + +#include + +#include + + +void idt_init(void); + +void pic_remap(void); + +void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags); + +void exception_handler(registers_t* regs); + + +#endif diff --git a/files/irq.c b/files/irq.c new file mode 100644 index 0000000..1a7e39d --- /dev/null +++ b/files/irq.c @@ -0,0 +1,69 @@ +#include +#include +#include +#include + +#include + +#define MAX_IRQ_HANDLERS 128 /* the maximum number of irq handlers */ + + +typedef struct { + uint32_t irq_no; + irq_func_t func; +} irq_handler_t; + +uint32_t num_irq_handlers = 0; +irq_handler_t handler_list[MAX_IRQ_HANDLERS]; + +static volatile uint32_t num_irqs_missed = 0; + +void irq_init(void) +{ + for (int i = 0; i < MAX_IRQ_HANDLERS; i++) + { + handler_list[i].irq_no = 0; + handler_list[i].func = NULL; + } + set_irq_handler(0, (irq_func_t) pit_handler); + set_irq_handler(1, (irq_func_t) ps2_keyboard_handler); +} + +void irq_handler(uint32_t irq, registers_t* regs) +{ + uint8_t funcs_called = 0; + + if (num_irq_handlers > 0) + { + for (unsigned int i = 0; i < num_irq_handlers; i++) + { + if (handler_list[i].irq_no == irq && handler_list[i].func != NULL) + { + handler_list[i].func(regs); + funcs_called++; + /* PIC IRQ acknowledgement happens in idt.c */ + } + } + } + + if (funcs_called == 0) + { + num_irqs_missed++; + } +} + +uint32_t get_interrupts_missed(void) +{ + return num_irqs_missed; +} + +void set_irq_handler(uint32_t num, irq_func_t handler) +{ + if (num < MAX_IRQ_HANDLERS) + { + handler_list[num].irq_no = num; + handler_list[num].func = handler; + + num_irq_handlers++; + } +} diff --git a/files/irq.h b/files/irq.h new file mode 100644 index 0000000..9bfc4f4 --- /dev/null +++ b/files/irq.h @@ -0,0 +1,43 @@ +#ifndef _IRQ_H +#define _IRQ_H + +#include +/* +typedef struct registers { + uint32_t ds, es, fs, gs; + + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; + + uint32_t int_no; + uint32_t err_code; + + uint32_t eip, cs, eflags; +} registers_t; +*/ + +typedef struct { + uint32_t ds, es, fs, gs; + + uint32_t eax, ecx, edx, ebx; + uint32_t esp, ebp, esi, edi; + + uint32_t int_no; + uint32_t err_code; + + uint32_t eip, cs, eflags; +} registers_t; + + +typedef void (*irq_func_t)(registers_t*); + + +void irq_init(void); + +void irq_handler(uint32_t irq, registers_t* regs); + +void set_irq_handler(uint32_t num, irq_func_t handler); +/*void add_irq_handler(uint32_t num, irq_func_t* handler);*/ + +uint32_t get_interrupts_missed(void); + +#endif diff --git a/files/isr.asm b/files/isr.asm new file mode 100644 index 0000000..47d2d9e --- /dev/null +++ b/files/isr.asm @@ -0,0 +1,154 @@ +[BITS 32] + +[GLOBAL isr_stub_table] +[GLOBAL irq_stub_table] +[GLOBAL interrupt_entry] + +extern interrupt_dispatcher + +section .text + +; ============================================================ +; COMMON INTERRUPT ENTRY +; ============================================================ + +interrupt_entry: + + ; Stack already contains: + ; err_code + ; int_no + ; eip + ; cs + ; eflags + + pusha ; eax, ecx, edx, ebx, esp, ebp, esi, edi + + ;push ds + ;push es + ;push fs + ;push gs + + push gs + push fs + push es + push ds + + + mov ax, 0x10 ; load kernel data selector + mov ds, ax + mov es, ax + mov fs, ax + mov gs, ax + + push esp ; pass pointer to registers_t + call interrupt_dispatcher + add esp, 4 + + pop gs + pop fs + pop es + pop ds + + popa + + add esp, 8 ; remove int_no + err_code + + iret + + +; ============================================================ +; IRQ STUBS +; ============================================================ + +%macro IRQ 1 +irq_stub_%+%1: + push dword 0 ; fake error code + push dword (32 + %1) ; vector number + jmp interrupt_entry +%endmacro + +IRQ 0 +IRQ 1 +IRQ 2 +IRQ 3 +IRQ 4 +IRQ 5 +IRQ 6 +IRQ 7 +IRQ 8 +IRQ 9 +IRQ 10 +IRQ 11 +IRQ 12 +IRQ 13 +IRQ 14 +IRQ 15 + +irq_stub_table: +%assign i 0 +%rep 16 + dd irq_stub_%+i +%assign i i+1 +%endrep + + +; ============================================================ +; EXCEPTION STUBS +; ============================================================ + +%macro ISR_NOERR 1 +isr_stub_%+%1: + push dword 0 ; fake error code + push dword %1 ; interrupt number + jmp interrupt_entry +%endmacro + +%macro ISR_ERR 1 +isr_stub_%+%1: + push dword %1 ; interrupt number + jmp interrupt_entry +%endmacro + + +; Exceptions 0–31 + +ISR_NOERR 0 +ISR_NOERR 1 +ISR_NOERR 2 +ISR_NOERR 3 +ISR_NOERR 4 +ISR_NOERR 5 +ISR_NOERR 6 +ISR_NOERR 7 +ISR_ERR 8 +ISR_NOERR 9 +ISR_ERR 10 +ISR_ERR 11 +ISR_ERR 12 +ISR_ERR 13 +ISR_ERR 14 +ISR_NOERR 15 +ISR_NOERR 16 +ISR_ERR 17 +ISR_NOERR 18 +ISR_NOERR 19 +ISR_NOERR 20 +ISR_NOERR 21 +ISR_NOERR 22 +ISR_NOERR 23 +ISR_NOERR 24 +ISR_NOERR 25 +ISR_NOERR 26 +ISR_NOERR 27 +ISR_NOERR 28 +ISR_NOERR 29 +ISR_ERR 30 +ISR_NOERR 31 + +isr_stub_table: +%assign i 0 +%rep 32 + dd isr_stub_%+i +%assign i i+1 +%endrep + diff --git a/files/kernel.c b/files/kernel.c new file mode 100644 index 0000000..1a530eb --- /dev/null +++ b/files/kernel.c @@ -0,0 +1,164 @@ +/* Check if the compiler thinks you are targeting the wrong operating system. */ +#if defined(__linux__) +#error "You are not using a cross-compiler, you will most certainly run into trouble" +#endif + +/* This tutorial will only work for the 32-bit ix86 targets. */ +#if !defined(__i386__) +#error "This kernel needs to be compiled with a ix86-elf compiler" +#endif + +#include + +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#include + +#include +#include +#include +/*#include */ +#include +#include +#include +/*#include */ +#include +#include + +#include + +#include + +#include + +#include + + +extern void _hang_asm(void); +extern void _sti_asm(void); + +void idle_task(void) +{ + while (1) + asm volatile("hlt"); +} + + +void kernel_main(multiboot_info_t* mbd, uint32_t magic) +{ + + /* --- BEGIN INITIALIZATION SECTION --- */ + + /* We need to initialize the terminal so that any error/debugging messages show. */ + terminal_initialize(); + + printf("Loading Espresso %s... ", KERNEL_VERSION); + +#ifdef _DEBUG + printf("[ DEBUG BUILD ]"); +#endif + + printf("\n"); + + terminal_setcolor(VGA_COLOR_RED); + + /* Make sure the magic number matches for memory mapping */ + if(magic != MULTIBOOT_BOOTLOADER_MAGIC) + { + printf("[ ERROR ] invalid magic number!\n"); + _hang_asm(); + } + + /* Check bit 6 to see if we have a valid memory map */ + if(!(mbd->flags >> 6 & 0x1)) + { + printf("[ ERROR ] invalid memory map given by GRUB bootloader\n"); + _hang_asm(); + } + + gdt_install(false); + + pic_remap(); /* must be done before idt_init() */ + + idt_init(); + + _sti_asm(); + + irq_init(); /* MUST be done after pic_remap() and idt_init() */ + + terminal_setcolor(VGA_COLOR_GREEN); + + pmm_init(mbd); + + paging_init(); + + heap_init(0xC2000000, 0x80000); + +#ifdef _DEBUG + printd("Testing SSE...\n"); +#endif + int32_t sse_test_result = test_sse(); + if (sse_test_result != 0) + { + printf("[ SSE ] SSE test failed with RV %d\n", sse_test_result); + } + else + { +#ifdef _DEBUG + printd("SSE test passed\n"); +#endif + } + + pit_init(); + + keyboard_init(); + + ide_initialize(); + + pci_init(); + + scheduler_init(); + + /* --- END INITIALIZATION SECTION --- */ + + + terminal_setcolor(VGA_COLOR_LIGHT_GREEN); + + printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION); + + //terminal_clear(); + + create_task(kshell_start); + create_task(idle_task); + + extern task_t* task_list; + extern task_t* current_task; + + current_task = task_list; + + printf("in kernel_main\n"); + + /*extern void terminal_clear(void); + + terminal_clear(); + + kshell_start(1, NULL);*/ + + for(;;) /* Loop infinitely. We only do something when an interrupt/syscall happens now. */ + { + asm volatile("hlt" ::: "memory"); + } +} diff --git a/files/pit.c b/files/pit.c new file mode 100644 index 0000000..e433648 --- /dev/null +++ b/files/pit.c @@ -0,0 +1,62 @@ +#include +#include +#include + +#include + +#include + + +#define PIT_CHANNEL0 0x40 +#define PIT_COMMAND 0x43 +#define PIT_IRQ_LINE 0 +#define PIT_FREQUENCY_BASE 1193182 + +volatile uint64_t pit_ticks = 0; +bool pit_initialized = false; + +void pit_init(void) +{ +#ifdef _DEBUG + printf("[ PIT ] Initializing the PIT...\n"); +#endif + + uint16_t divisor = (uint16_t) 1193; + + /* Send command byte */ + outb(PIT_COMMAND, 0x36); /* Channel 0, low/high byte, mode 3 (square wave), binary */ + + /* Send divisor low and high byte */ + outb(PIT_CHANNEL0, (uint8_t)(divisor & 0xFF)); /* Low byte */ + outb(PIT_CHANNEL0, (uint8_t)((divisor >> 8) & 0xFF)); /* High byte */ + + pit_initialized = true; + +#ifdef _DEBUG + printf("[ PIT ] PIT Initialized\n"); +#endif +} + +void pit_handler(void) +{ + pit_ticks++; +} + +/*void pit_sleep(uint64_t ms) +{ + uint64_t target = pit_ticks + ms; + while (pit_ticks < target) + { + asm volatile ("hlt"); + } +}*/ + +void pit_sleep(uint64_t ms) +{ + extern task_t* current_task; + + current_task->wakeup_tick = pit_ticks + ms; + current_task->state = TASK_SLEEPING; + + asm volatile("int $32"); /* force reschedule immediately */ +} diff --git a/files/scheduler.c b/files/scheduler.c new file mode 100644 index 0000000..902cc2d --- /dev/null +++ b/files/scheduler.c @@ -0,0 +1,158 @@ +#include +#include + +#include + +#include + +#define STACK_SIZE 4096 + +task_t* task_list = NULL; +task_t* current_task = NULL; +uint32_t next_task_id = 1; + +static void schedule(void); + +/* scheduler init */ +void scheduler_init(void) +{ + set_irq_handler(0, (irq_func_t) scheduler_tick); +} + +static void schedule(void) +{ + if (!task_list) + { + return; + } + + /* wake sleeping tasks */ + task_t* t = task_list; + + extern uint64_t pit_ticks; + + do + { + if (t->state == TASK_SLEEPING && pit_ticks >= t->wakeup_tick) + { + t->state = TASK_READY; + } + + t = t->next; + } + while (t != task_list); + + /* find next ready task */ + task_t* start = current_task; + + do + { + current_task = current_task->next; + + if (current_task->state == TASK_READY) + { + return; + } + } + while (current_task != start); +} + + +/* tick handler */ +void scheduler_tick(registers_t* regs) +{ + if (!task_list) + { + printf("!task_list\n"); + + return; + } + + if (!current_task) + { + printf("!current_task\n"); + current_task = task_list; + } + + /* save current task state */ + *(current_task->regs) = *regs; + + /* pick next */ + schedule(); + + /* load next task state */ + *regs = *(current_task->regs); +} + +/* task creation */ +task_t* create_task(void (*entry)()) +{ + task_t* task = malloc(sizeof(task_t)); + + if (!task) + { + return NULL; + } + + memset(task, 0, sizeof(task_t)); + + /* allocate stack */ + uint8_t* stack = malloc(STACK_SIZE); + + if (!stack) + { + free(task); + return NULL; + } + + printf("Creating task %i @ %p\n", next_task_id, entry); + + /* + align stack to 16 bytes for safety (SSE friendly). + stack grows downward. + */ + uintptr_t stack_top = (uintptr_t)(stack + STACK_SIZE); + stack_top &= ~0xF; + + registers_t* regs = (registers_t*) (stack_top - sizeof(registers_t)); + memset(regs, 0, sizeof(registers_t)); + + /* initialize register frame */ + regs->eip = (uint32_t) entry; + regs->cs = 0x08; /* Kernel code segment */ + regs->eflags = 0x202; /* IF=1 */ + + task->id = next_task_id++; + task->regs = regs; + task->stack_base = (uint32_t*) stack; + task->state = TASK_READY; + + /* insert into circular list */ + if (!task_list) + { + task_list = task; + task->next = task; + } + else + { + task_t* last = task_list; + while (last->next != task_list) + { + last = last->next; + } + + last->next = task; + task->next = task_list; + } + + printf("Task %i @ %p created successfully\n", next_task_id - 1, entry); + + return task; +} + +/* task destruction */ +void destroy_task(task_t* task) +{ + free(task->stack_base); + free(task); +} diff --git a/files/scheduler.h b/files/scheduler.h new file mode 100644 index 0000000..c2f7a92 --- /dev/null +++ b/files/scheduler.h @@ -0,0 +1,32 @@ +#ifndef _SCHEDULER_H +#define _SCHEDULER_H + +#include + +#include + +typedef enum { + TASK_READY, + TASK_RUNNING, + TASK_SLEEPING, + TASK_BLOCKED, + TASK_TERMINATED, +} task_state_t; + +typedef struct task { + uint32_t id; + + registers_t* regs; /* pointer to saved register frame */ + uint32_t* stack_base; /* original malloc() pointer */ + + task_state_t state; + struct task* next; + + uint64_t wakeup_tick; +} task_t; + +void scheduler_init(void); +task_t* create_task(void (*entry)()); +void scheduler_tick(registers_t* regs); + +#endif diff --git a/include/arch/x86/intrin.h b/include/arch/x86/intrin.h new file mode 100644 index 0000000..2e0e653 --- /dev/null +++ b/include/arch/x86/intrin.h @@ -0,0 +1,15 @@ +#ifndef _INTRINSICS_H +#define _INTRINSICS_H + +#include + +static inline uint64_t rdtsc(void) +{ + uint32_t lo, hi; + asm volatile ("rdtsc" : "=a"(lo), "=d"(hi)); + + return ((uint64_t) hi << 32) | lo; +} + + +#endif diff --git a/include/drivers/audio/pcspeaker.h b/include/drivers/audio/pcspeaker.h new file mode 100644 index 0000000..8af3851 --- /dev/null +++ b/include/drivers/audio/pcspeaker.h @@ -0,0 +1,11 @@ +#ifndef ESPRESSO_PC_SPEAKER_H +#define ESPRESSO_PC_SPEAKER_H + +#include + +void play_sound(uint32_t nfrequence); +void stop_sound(void); + +void beep(void); + +#endif diff --git a/include/drivers/elf.h b/include/drivers/elf.h index 0e68a98..66133ad 100644 --- a/include/drivers/elf.h +++ b/include/drivers/elf.h @@ -9,35 +9,37 @@ #define PT_LOAD 1 typedef struct { - unsigned char e_ident[EI_NIDENT]; - uint16_t e_type; - uint16_t e_machine; - uint32_t e_version; - uint32_t e_entry; - uint32_t e_phoff; - uint32_t e_shoff; - uint32_t e_flags; - uint16_t e_ehsize; - uint16_t e_phentsize; - uint16_t e_phnum; - uint16_t e_shentsize; - uint16_t e_shnum; - uint16_t e_shstrndx; + unsigned char e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; } Elf32_Ehdr; typedef struct { - uint32_t p_type; - uint32_t p_offset; - uint32_t p_vaddr; - uint32_t p_paddr; - uint32_t p_filesz; - uint32_t p_memsz; - uint32_t p_flags; - uint32_t p_align; + uint32_t p_type; + uint32_t p_offset; + uint32_t p_vaddr; + uint32_t p_paddr; + uint32_t p_filesz; + uint32_t p_memsz; + uint32_t p_flags; + uint32_t p_align; } Elf32_Phdr; +typedef int (*elf_entry_t)(void); + typedef struct { - void* entry_point; + elf_entry_t entry_point; } elf_executable_t; elf_executable_t* load_elf32(void* elf_data); diff --git a/include/drivers/idt.h b/include/drivers/idt.h index 8921162..4fe1493 100644 --- a/include/drivers/idt.h +++ b/include/drivers/idt.h @@ -1,13 +1,18 @@ #ifndef _IDT_H #define _IDT_H +#include + #include void idt_init(void); + void pic_remap(void); + void idt_set_descriptor(uint8_t vector, void* isr, uint8_t flags); -void exception_dispatcher(uint32_t int_no, uint32_t err_code); + +void exception_handler(registers_t* regs); #endif diff --git a/include/drivers/irq.h b/include/drivers/irq.h index 13629a3..28bff4f 100644 --- a/include/drivers/irq.h +++ b/include/drivers/irq.h @@ -3,13 +3,28 @@ #include -typedef void (*irq_func_t)(void); +typedef struct { + uint32_t ds, es, fs, gs; + + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; + + uint32_t int_no; + uint32_t err_code; + + uint32_t eip; + uint32_t cs; + uint32_t eflags; +} registers_t; + +typedef registers_t* (*irq_func_t)(registers_t*); void irq_init(void); -void irq_handler(uint8_t irq_number); +registers_t* irq_handler(uint32_t irq, registers_t* regs); -void set_irq_handler(uint32_t num, irq_func_t* handler); -void add_irq_handler(uint32_t num, irq_func_t* handler); +void set_irq_handler(uint32_t num, irq_func_t handler); +/*void add_irq_handler(uint32_t num, irq_func_t* handler);*/ + +uint32_t get_interrupts_missed(void); #endif diff --git a/include/drivers/keyboard.h b/include/drivers/keyboard.h new file mode 100644 index 0000000..6884315 --- /dev/null +++ b/include/drivers/keyboard.h @@ -0,0 +1,10 @@ +#ifndef _KEYBOARD_DRIVER_H +#define _KEYBOARD_DRIVER_H + +#include + +int init_keyboard(void); + +registers_t* keyboard_handler(registers_t* regs); + +#endif diff --git a/include/drivers/pit.h b/include/drivers/pit.h index b4a3f5f..510b4ec 100644 --- a/include/drivers/pit.h +++ b/include/drivers/pit.h @@ -3,10 +3,11 @@ #include -extern volatile uint64_t pit_ticks; + +#include void pit_init(void); -void pit_handler(void); +registers_t* pit_handler(registers_t* regs); void pit_sleep(uint64_t ms); #endif diff --git a/include/drivers/ps2_keyboard.h b/include/drivers/ps2_keyboard.h index b5f78ed..76ed2ac 100644 --- a/include/drivers/ps2_keyboard.h +++ b/include/drivers/ps2_keyboard.h @@ -23,7 +23,9 @@ typedef enum { typedef void (*ps2_hook_t)(char); void keyboard_init(void); -void keyboard_handler(void); +registers_t* ps2_keyboard_handler(registers_t* regs); + +void set_use_new_tty(bool t); char get_char(void); uint16_t get_key(void); diff --git a/include/fs/ekfs.h b/include/fs/ekfs.h new file mode 100644 index 0000000..af43c41 --- /dev/null +++ b/include/fs/ekfs.h @@ -0,0 +1,37 @@ +//#ifndef _ESPRESSO_KERNEL_FS_H +#if 0 +#define _ESPRESSO_KERNEL_FS_H + +#include + +#define EKFS_FILENAME_MAX_LEN 64 + +enum { + EKFS_E_FILETOOSMALL = -16; +}; + +struct ekfs_inode { + char i_name[EKFS_FILENAME_MAX_LEN]; + + uint64_t i_start; /* LBA48 */ + size_t i_len; /* rounded up to the nearest multiple of 512 */ +} __attribute__((packed)); + +struct ekfs_ops { + int (*read)(struct ekfs_file*, void*, size_t); + int (*write)(struct ekfs_file*, void*, size_t); +}; + +struct ekfs_file { + struct ekfs_inode* f_inode; + + size_t f_offset; + size_t f_refcount; + + struct ekfs_ops f_ops; +}; + + +int ekfs_read(struct ekfs_file* __f, void* __b, size_t __l); + +#endif diff --git a/include/fs/fat16.h b/include/fs/fat16.h new file mode 100644 index 0000000..465da8a --- /dev/null +++ b/include/fs/fat16.h @@ -0,0 +1,78 @@ +#ifndef _FAT16_H +#define _FAT16_H + +#include +#include +#include + +#define FAT16_MAX_FILENAME 12 /* 8.3 + null */ +#define SECTOR_SIZE 512 + +typedef struct { + uint16_t bytes_per_sector; + uint8_t sectors_per_cluster; + uint16_t reserved_sector_count; + uint8_t num_fats; + uint16_t root_entry_count; + uint16_t total_sectors_16; + uint16_t sectors_per_fat; + uint32_t fat_start_lba; + uint32_t root_dir_lba; + uint32_t data_start_lba; + uint32_t total_sectors; +} fat16_fs_t; + +typedef struct { + char name[FAT16_MAX_FILENAME]; /* 8.3 format */ + uint8_t attr; + uint16_t first_cluster; + uint32_t size; +} fat16_file_t; + +int fat16_mount(uint8_t drive); + +int fat16_find_file(const char* name, fat16_file_t* out_file); + +int fat16_create_file(const char* name, fat16_file_t* out_file); +int fat16_delete_file(const char* filename); + +int fat16_read_file(fat16_file_t* file, void* buffer); +int fat16_write_file(fat16_file_t* file, const void* buffer, uint32_t size); + + +/* + Small helper function that converts a normal filename like "test.txt" into FAT16 8.3 uppercase format padded with spaces. + This makes creating and writing files much easier. +*/ +static void filename_to_83(const char* input, char out[12]) +{ + memset(out, ' ', 11); + out[11] = '\0'; + + /* Find dot */ + const char* dot = strchr(input, '.'); + size_t name_len = dot ? (size_t) (dot - input) : strlen(input); + + if (name_len > 8) + { + name_len = 8; + } + + for (size_t i = 0; i < name_len; i++) + { + out[i] = toupper((unsigned char)input[i]); + } + + if (dot) + { + size_t ext_len = strlen(dot + 1); + if (ext_len > 3) ext_len = 3; + for (size_t i = 0; i < ext_len; i++) + { + out[8 + i] = toupper((unsigned char)dot[1 + i]); + } + } +} + + +#endif diff --git a/include/kernel/kshell.h b/include/kernel/kshell.h index f5e18e7..8e3cf2a 100644 --- a/include/kernel/kshell.h +++ b/include/kernel/kshell.h @@ -1,8 +1,6 @@ #ifndef _KERNEL_SHELL_H #define _KERNEL_SHELL_H -#include - -int kshell_start(int argc, char** argv); +void kshell_start(void); #endif diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h new file mode 100644 index 0000000..3f2135b --- /dev/null +++ b/include/kernel/syscall.h @@ -0,0 +1,111 @@ +#ifndef _ESPRESSO_SYSCALL_H +#define _ESPRESSO_SYSCALL_H + +#include + +#define SYSCALL_INT 0x30 + +enum { + SYS_MAP_PAGE = 0, /* void map_page(void* phys_addr, void* virt_addr); */ + SYS_PMM_ALLOC_PAGE, /* void* pmm_alloc_page(void); */ + SYS_PMM_FREE_PAGE, /* void pmm_free_page(void* addr); */ + SYS_SERIAL_WRITE, /* void serial_write(char a); */ + SYS_SERIAL_READ, /* char serial_read(void); */ + SYS_SERIAL_PUTS, /* void serial_puts(const char* s); */ + SYS_USE_SERIAL, /* bool use_serial(void); */ + SYS_TERMINAL_SCROLL, /* void terminal_scroll(void); */ + SYS_TERMINAL_CLEAR, /* void terminal_clear(void); */ + SYS_TERMINAL_SET_CURSOR, /* void terminal_set_cursor(uint16_t row, uint16_t column); */ + SYS_TERMINAL_GET_CURSOR, /* void terminal_get_cursor(int* row, int* column); */ + SYS_TERMINAL_WRITE, /* void terminal_write(const char* data, size_t size); */ + SYS_TERMINAL_WRITESTRING, /* void terminal_writestring(const char* data) */ + SYS_TERMINAL_DEBUG_WRITESTRING, /* void terminal_debug_writestring(const char* data); */ + SYS_TERMINAL_PUTCHAR, /* void terminal_putchar(char c); */ + SYS_TERMINAL_PUTENTRYAT, /* void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y); */ + SYS_TERMINAL_GETCOLOR, /* uint8_t terminal_getcolor(void); */ + SYS_TERMINAL_SETCOLOR, /* void terminal_setcolor(uint8_t color); */ + SYS_READ, /* int read(uint32_t fd, void* data, size_t max_len); */ + SYS_WRITE, /* int write(uint32_t fd, void* data, size_t len); */ + __ENUM_END_MARKER__, +}; + + +#define syscall0(num) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num) \ + : "memory" \ + ); \ + ret; \ +}) + +/* syscall 1 */ +#define syscall1(num, a) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall2(num, a, b) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall3(num, a, b, c) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall4(num, a, b, c, d) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c), "S"(d) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall5(num, a, b, c, d, e) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c), "S"(d), "D"(e) \ + : "memory" \ + ); \ + ret; \ +}) + +/* some macros for commonly used functions */ +#define syscall_terminal_writestring(ptr) syscall1(SYS_TERMINAL_WRITESTRING, ptr); +#define syscall_terminal_putchar(chr) syscall1(SYS_TERMINAL_PUTCHAR, chr); +#define syscall_map_page(phys, virt) syscall2(SYS_MAP_PAGE, phys, virt); +#define syscall_pmm_alloc_page() syscall0(SYS_PMM_ALLOC_PAGE); +#define syscall_pmm_free_page(addr) syscall1(SYS_PMM_FREE_PAGE, addr); + +void init_sysints(void); + +registers_t* int16_handler(registers_t* regs); + +#endif diff --git a/include/kincl.h b/include/kincl.h index 0141dec..d88f37d 100644 --- a/include/kincl.h +++ b/include/kincl.h @@ -3,7 +3,8 @@ #define ESPRESSO_KERNEL_ -#define KERNEL_VERSION "0.0.2a" +#define KERNEL_VERSION "0.0.2c" +#define KERNEL_RELEASE_YEAR "2026" #define _STATE_NORMAL 0 #define _STATE_HANDLED 1 @@ -18,4 +19,14 @@ #define __noreturn __attribute__((noreturn)) #define __section(x) __attribute__((section(x))) +#define __noreturn __attribute__((noreturn)) + +extern void _cli_asm(void); +extern void _sti_asm(void); + +#define IRQ_DISABLE() _cli_asm(); +#define IRQ_ENABLE() _sti_asm(); + +//#define DEBUG_USE_SSE2 + #endif diff --git a/include/math/random.h b/include/math/random.h new file mode 100644 index 0000000..cce98c5 --- /dev/null +++ b/include/math/random.h @@ -0,0 +1,15 @@ +#ifndef _RANDOM_H +#define _RANDOM_H + +#include + +void seed_rand(uint32_t seed); + +uint32_t uirand(void); /* 32 bits / 4 bytes */ +uint64_t ulrand(void); /* 64 bits / 8 bytes */ + +/* get a number between 0 and max-1 */ +uint32_t uirand_range(uint32_t max); +uint64_t ulrand_range(uint64_t max); + +#endif diff --git a/include/new_tty.h b/include/new_tty.h new file mode 100644 index 0000000..d1c96ca --- /dev/null +++ b/include/new_tty.h @@ -0,0 +1,73 @@ +#ifndef _TTY_H +#define _TTY_H + + +#include + +#include +#include + + +#define TTY_BUFFER_SIZE 4096 +#define MAX_TTYS 8 /* to make things easy, might change later */ + +#define TTY_ECHO 0x10 /* 0b00010000 */ +#define TTY_PASSWORD 0x20 /* 0b00100000 */ +#define TTY_ACTIVE 0x01 /* 0b00000001 */ + +#define TTY_CANONICAL 0x40 /* 0b01000000 */ + + +#define TTY_NULL 0x80 /* 0b10000000 --- used to end the list of tty_t structs in the ttys array */ + +#define TTY_NORMAL TTY_ECHO | TTY_ACTIVE | TTY_CANONICAL + +#define MODIFIER_CAPS 0x01 /* 0b00000001 */ +#define MODIFIER_CAPS_DESTROY 0b11111110 +#define MODIFIER_SHIFT 0x02 /* 0b00000010 */ +#define MODIFIER_SHIFT_DESTROY 0b11111101 +#define MODIFIER_ALT 0x04 /* 0b00000100 */ +#define MODIFIER_ALT_DESTROY 0b11111011 +#define MODIFIER_LCTRL 0x10 /* 0b00010000 */ +#define MODIFIER_LCTRL_DESTROY 0b11101111 +#define MODIFIER_RCTRL 0x0 /* 0b00100000*/ +#define MODIFIER_RCTRL_DESTROY 0b11011111 + + +typedef struct tty_t { + char input_buffer[TTY_BUFFER_SIZE]; + size_t head; + size_t tail; + + uint32_t flags; + + bool canonical; + bool line_ready; + + spinlock_t lock; + + pid_t foreground_pgid; /* not used yet */ +} tty_t; + +/* essentially, key is non-zero if a key like the up arrow is pressed, otherwise c is the char that was entered */ +struct keyevent { + uint8_t key; + char c; +}; + +int init_tty(void); + +ssize_t tty_read(tty_t* tty, char* buf, size_t count); +ssize_t tty_read_active(char* buf, size_t count); + +tty_t* get_active_tty(void); +tty_t* tty_get_active(void); + +tty_t* make_tty(uint32_t flags); + +void tty_receive_char(char c, uint32_t kbd_mod); +char tty_translate_char(char c, uint32_t modifiers); + +void tty_input_char(tty_t* tty, char c); + +#endif diff --git a/include/printf.h b/include/printf.h index 6ca76a1..daacc9f 100644 --- a/include/printf.h +++ b/include/printf.h @@ -1,10 +1,10 @@ #ifndef _PRINTF_H #define _PRINTF_H -#include +//#include #include -#include /* Only for the vga_color enum */ +//#include /* Only for the vga_color enum */ void printwc(const char*, uint8_t); diff --git a/include/processes.h b/include/processes.h index 9593ec7..14ed8d9 100644 --- a/include/processes.h +++ b/include/processes.h @@ -5,15 +5,17 @@ #include + +typedef uint32_t pid_t; + typedef struct process { - int32_t id; - int32_t group; + pid_t id; + pid_t group; elf_executable_t* exe; - - struct process* next; } process_t; -int32_t make_process(char* name, char* group, elf_executable_t* exe); + +pid_t make_process(char* name, char* group, elf_executable_t* exe); #endif diff --git a/include/scheduler.h b/include/scheduler.h new file mode 100644 index 0000000..bc4ab5b --- /dev/null +++ b/include/scheduler.h @@ -0,0 +1,21 @@ +#ifndef _SCHEDULER_H +#define _SCHEDULER_H + + +#include + +#include + +typedef struct task { + registers_t* regs; /* saved interrupt frame */ + uint32_t id; + struct task* next; +} task_t; + +void init_scheduler(void); + +registers_t* schedule(registers_t* regs); + +task_t* create_task(void (*entry)()); + +#endif diff --git a/include/stdio.h b/include/stdio.h index 478ec97..369518c 100644 --- a/include/stdio.h +++ b/include/stdio.h @@ -4,10 +4,23 @@ #include #include +#define STDIN 0 +#define STDOUT 1 +#define STDERR 2 + +int read(uint32_t fd, void* data, size_t max_len); +int write(uint32_t fd, void* data, size_t len); + char getchar(void); char* getstring(void); char* gets(void); /* Use this instead of getstring() */ +int getstr(char* dest); + +char* gets_new(int* num); + +void putc(char c); + static inline void putchar(char c) { printf("%c", c); diff --git a/include/string.h b/include/string.h index 2ffee08..d7c8b3a 100644 --- a/include/string.h +++ b/include/string.h @@ -17,8 +17,10 @@ char* strdup(const char* s); char* strtok(char* str, const char* delim); char* strchr(const char* s, int c); -/* this function is NOT in the standard C library */ +/* these functions are NOT in the standard C library */ int num_strchr(const char* s, int c); +char* strnlstrip(const char* __s); +void strlnstripip(char* s); void lowers(char* str); void uppers(char* str); diff --git a/include/sync.h b/include/sync.h new file mode 100644 index 0000000..128d533 --- /dev/null +++ b/include/sync.h @@ -0,0 +1,14 @@ +#ifndef _SYNC_H +#define _SYNC_H + +typedef struct { + volatile int locked; +} spinlock_t; + + +void spinlock_init(spinlock_t* lock); + +void spin_lock(spinlock_t* lock); +void spin_unlock(spinlock_t* lock); + +#endif diff --git a/include/tty.h b/include/tty.h index 6d5b576..6f68a11 100644 --- a/include/tty.h +++ b/include/tty.h @@ -1,5 +1,5 @@ -#ifndef _TTY_H -#define _TTY_H +#ifndef TTY_H +#define TTY_H #include @@ -32,4 +32,7 @@ void terminal_set_cursor(uint16_t row, uint16_t column); void terminal_get_cursor(int* row, int* column); void terminal_update_cursor(void); + +void terminal_putcharat(char c, uint16_t row, uint16_t column); + #endif diff --git a/include/types.h b/include/types.h index 4b3a71f..c0dfbde 100644 --- a/include/types.h +++ b/include/types.h @@ -5,6 +5,11 @@ #include #include +#define ARG64_LO(x) ((uint32_t)(x)) +#define ARG64_HI(x) ((uint32_t)((x) >> 32)) + +#define TOGGLE_BIT(x, bit) ((x) ^= (1U << (bit))) + typedef unsigned char uchar; typedef uint8_t u8; @@ -12,4 +17,19 @@ typedef uint16_t u16; typedef uint32_t u32; typedef uint64_t u64; +typedef int8_t i8; +typedef int16_t i16; +typedef int32_t i32; +typedef int64_t i64; + +/* this might not be POSIX compatable. */ +typedef uint32_t size_t; +typedef int32_t ssize_t; + +#if 0 +#if sizeof(size_t) != sizeof(ssize_t) +#error "size_t is a different size than ssize_t" +#endif +#endif + #endif diff --git a/kernel/intro.c b/kernel/intro.c index 2689c87..db6a232 100644 --- a/kernel/intro.c +++ b/kernel/intro.c @@ -13,11 +13,9 @@ char char_entered = 0x00; void intro_begin(void) { - extern char* kernel_version; - - char* fin = (char*) malloc(strlen(kernel_version) + 6); - memset(fin, 0, (strlen(kernel_version) + 5)); - strcpy(fin, kernel_version); + char* fin = (char*) malloc(strlen(KERNEL_VERSION) + 6); + memset(fin, 0, (strlen(KERNEL_VERSION) + 5)); + strcpy(fin, KERNEL_VERSION); #ifdef _DEBUG strcat(fin, " DEBUG"); diff --git a/kernel/kernel.c b/kernel/kernel.c index d236534..2642f90 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -16,6 +16,12 @@ #include #include +#include + +#include +#include + +#include #include @@ -23,54 +29,41 @@ #include #include +#include + #include #include #include +#include #include /*#include */ #include #include #include -#include +/*#include */ #include -#include +#ifdef DEBUG_USE_SSE2 #include +#endif #include #include -#include - -#define DEBUG - extern void _hang_asm(void); extern void _sti_asm(void); -char* espresso_str = "" -"####### ##### ###### ###### ####### ##### ##### #######\n" -"# # # # # # # # # # # # # #\n" -"# # # # # # # # # # #\n" -"##### ##### ###### ###### ##### ##### ##### # #\n" -"# # # # # # # # # #\n" -"# # # # # # # # # # # # #\n" -"####### ##### # # # ####### ##### ##### #######\n"; - -char* kernel_version = "0.0.2a"; - - void kernel_main(multiboot_info_t* mbd, uint32_t magic) -{ - +{ /* --- BEGIN INITIALIZATION SECTION --- */ /* We need to initialize the terminal so that any error/debugging messages show. */ terminal_initialize(); - printf("Loading Espresso %s... ", kernel_version); + printf("Loading Espresso %s... ", KERNEL_VERSION); #ifdef _DEBUG printf("[ DEBUG BUILD ]"); @@ -96,12 +89,8 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic) gdt_install(false); - pic_remap(); - + pic_remap(); /* must be done before idt_init() */ idt_init(); - - _sti_asm(); - irq_init(); /* MUST be done after pic_remap() and idt_init() */ terminal_setcolor(VGA_COLOR_GREEN); @@ -112,44 +101,65 @@ void kernel_main(multiboot_info_t* mbd, uint32_t magic) heap_init(0xC2000000, 0x80000); +#ifdef DEBUG_USE_SSE2 +#ifdef _DEBUG printd("Testing SSE...\n"); +#endif int32_t sse_test_result = test_sse(); if (sse_test_result != 0) { - printf("[ DEBUG ] SSE test failed with RV %d\n", sse_test_result); + printf("[ SSE ] SSE test failed with RV %d\n", sse_test_result); } else { +#ifdef _DEBUG printd("SSE test passed\n"); +#endif } +#endif pit_init(); + + int j = init_tty(); + + if (j != 0) + { + printwc("[ ERROR ] init_tty failed\n", VGA_COLOR_RED); + while (1) + { + asm volatile ("nop" ::: "memory"); + } + } - keyboard_init(); + //keyboard_init(); + init_keyboard(); ide_initialize(); pci_init(); - + + init_sysints(); + + /*init_scheduler();*/ + + _sti_asm(); + /* --- END INITIALIZATION SECTION --- */ - + + terminal_setcolor(VGA_COLOR_LIGHT_GREEN); - printf("Guten tag and welcome to Espresso %s\n", kernel_version); + printf("Guten tag and welcome to Espresso %s\n", KERNEL_VERSION); - sleep(1000); - - intro_begin(); - - /*extern void terminal_clear(void); + extern void terminal_clear(void); terminal_clear(); - kshell_start(1, NULL);*/ + kshell_start(); - while (true) + for(;;) /* Loop infinitely. We only do something when an interrupt/syscall happens now. */ { - /* Loop infinitely. We only do something when a syscall happens now. */ + asm volatile("hlt" ::: "memory"); } } diff --git a/kernel/kshell.c b/kernel/kshell.c index f335c8d..467aee9 100644 --- a/kernel/kshell.c +++ b/kernel/kshell.c @@ -6,6 +6,12 @@ #include #include +#include + +#include + +#include + #include #include @@ -15,7 +21,7 @@ const char* shell_version = "0.0.2"; char* prompt = NULL; int command = -1; -bool _debug = false; +bool _debug = true; int execute(void); @@ -44,18 +50,7 @@ static void print_intro(void) printf("CPU: %s\n", _temp == NULL ? "No info" : _temp); printf("CPU vendor: %s\n", temp_ == NULL ? "No info" : temp_); - printf("\nCopyright 2025 David J Goeke\n"); -} - -static void parse_opts(int argc, char** argv) -{ - for (int i = 0; i < argc; i++) - { - if (strcmp(argv[i], "--color") == 0) - { - - } - } + printf("\nCopyright %s David J Goeke\n", KERNEL_RELEASE_YEAR); } static char* commands[] = { @@ -76,19 +71,28 @@ static char* commands[] = { "printrandom", - "acm", /* ACcess Memory */ - "testfat16", + "printc", + + "testscheduler", + + "readfat16", + + "help", + + "exec", + + "int16test", + NULL, }; -#define NUM_COMMANDS 15 /* Yes, including the NULL */ +const int NUM_COMMANDS = 19; /* Yes, including the NULL */ -int kshell_start(int argc, char** argv) +void kshell_start(void) { - (void)argc; - (void)argv; + printf("Welcome to the kshell!\n"); prompt = strdup(">"); @@ -102,7 +106,17 @@ int kshell_start(int argc, char** argv) { printf("%s ", prompt); - i = gets(); + /*i = gets();*/ + int j = 0; + i = gets_new(&j); + + if (j == 0) + { + printf("Error?\n"); + break; + } + + i = strnlstrip(i); command = -1; @@ -165,14 +179,14 @@ int kshell_start(int argc, char** argv) } while (1); - if (i != NULL) + if (i) { free(i); } printf("Goodbye!\n"); - return 0; + return; } /* @@ -194,7 +208,7 @@ int kshell_start(int argc, char** argv) "printrandom", - "acm", + "testfat16", NULL, }; @@ -321,31 +335,6 @@ int execute(void) break; } case 12: { - printf("Enter hexadecimal address to access: "); - char* g = gets(); - - int val = atoi(g); - - if (val == 0) - { - printf("Improper/Malformed string entered\n"); - - break; - } - else if (val < 0x100000) - { - printf("Invalid address, must be higher than 0x100000\n"); - - break; - } - - int val_ = *((int*) val); - - printf("value at %u: %i\n", val, val_); - - break; - } - case 13: { int retv = fat16_mount(0); if (retv != 0) @@ -402,6 +391,151 @@ int execute(void) fat16_delete_file(fat_name); + break; + } + case 13: + { + printf("Enter char to print in decimal: "); + char* g = gets(); + + int val = atoi(g); + + if (*g == '\0') + { + printf("Empty string entered\n"); + break; + } + + printf("%c\n", (char) val); + + break; + } + case 14: + { +#if 0 + void taskA() { while (1) printf("A"); } + void taskB() { while (1) printf("B"); } + + create_task(taskA); + create_task(taskB); +#endif + + break; + } + case 15: + { + char* filename = "t.bin"; + + int retv = fat16_mount(0); + + if (retv != 0) + { + printf("There was an error while mounting volume 0.\n"); + + break; + } + + printf("Volume 0 mounted successfully.\n"); + + char fat_name[12]; + fat16_file_t file; + + filename_to_83(filename, fat_name); + retv = fat16_find_file(fat_name, &file); + + if (retv != 0) + { + printf("file %s could not be found\n", filename); + break; + } + + uint8_t buffer[256]; + memset(buffer, 0, sizeof(buffer)); + + retv = fat16_read_file(&file, buffer); + + if (retv != 0) + { + printf("Could not read file s\n", (char*) filename); + break; + } + + printf("read data: %s\n", (char*) buffer); + break; + } + case 16: + { + printf("Commands:\n"); + + for (int i = 0; i < NUM_COMMANDS; i++) + { + printf("%s\n", commands[i]); + } + + break; + } + case 17: + { + char* filename = "hello.elf"; + + printf("Loading and executing file %s\n", filename); + + int retv = fat16_mount(0); + + if (retv != 0) + { + printf("There was an error while mounting volume 0.\n"); + + break; + } + + printf("Volume 0 mounted successfully.\n"); + + char fat_name[12]; + fat16_file_t file; + + filename_to_83(filename, fat_name); + retv = fat16_find_file(fat_name, &file); + + if (retv != 0) + { + printf("file %s could not be found\n", filename); + break; + } + + uint8_t* buffer = malloc(file.size); + memset(buffer, 0, file.size); + + retv = fat16_read_file(&file, buffer); + + if (retv != 0) + { + printf("Could not read file s\n", (char*) filename); + break; + } + + printf("Parsing ELF headers\n"); + + elf_executable_t* f = load_elf32(buffer); + + printf("Attempting execution of executable...\n"); + + retv = f->entry_point(); + + printf("\nreturn value: %i\n", retv); + + break; + } + case 18: + { + printf("testing int 16\n"); + + const char* str = "HELLO!\n"; + + syscall1(SYS_TERMINAL_WRITESTRING, str); + + printf("test ran\n"); + break; } } diff --git a/kernel/syscall.c b/kernel/syscall.c new file mode 100644 index 0000000..a8fe380 --- /dev/null +++ b/kernel/syscall.c @@ -0,0 +1,118 @@ +#include +#include + +#include +#include + +#include + +#include + +#include + + +/* +Espresso has two types of syscalls. + +one: int 16, the only one I've worked on. should be able to be used in kernel code and user-space. +two: syscall/sysenter, the ones I haven't worked on because it has to do with userspace code. +*/ + + +/* +NOTE: passing arguments to fuctions +to pass args to functions, use all registers except eax, +so ebx is arg0, ecx arg1, edx arg2, esi arg3, edi arg4, ebp arg5 +*/ + +void init_sysints(void) +{ + /* actually nothing to do */ + + set_irq_handler(16, (irq_func_t) int16_handler); +} + +/* 0 in eax means success most of the time */ +registers_t* int16_handler(registers_t* regs) +{ + //printf("eax: %0x%x\n", regs->eax); + + uint32_t eax = regs->eax; + + if (eax >= __ENUM_END_MARKER__) + { + printf("Invalid system call %i\n", eax); + return regs; + } + + switch (eax) + { + case SYS_MAP_PAGE: + map_page((void*) regs->ebx, (void*) regs->ecx); + break; + case SYS_PMM_ALLOC_PAGE: + eax = (uint32_t) pmm_alloc_page(); + break; + case SYS_PMM_FREE_PAGE: + pmm_free_page((void*) regs->ebx); + break; + case SYS_SERIAL_WRITE: + serial_write(regs->ebx); + break; + case SYS_SERIAL_READ: + eax = serial_read(); + break; + case SYS_SERIAL_PUTS: + serial_puts((const char*) regs->ebx); + break; + case SYS_USE_SERIAL: + eax = use_serial(); + break; + case SYS_TERMINAL_SCROLL: + terminal_scroll(); + break; + case SYS_TERMINAL_CLEAR: + terminal_clear(); + break; + case SYS_TERMINAL_SET_CURSOR: + terminal_set_cursor(regs->ebx, regs->ecx); + break; + case SYS_TERMINAL_GET_CURSOR: + terminal_get_cursor((int*) regs->ebx, (int*) regs->ecx); + break; + case SYS_TERMINAL_WRITE: + terminal_write((const char*) regs->ebx, regs->ecx); + break; + case SYS_TERMINAL_WRITESTRING: + terminal_writestring((const char*) regs->ebx); + break; + case SYS_TERMINAL_DEBUG_WRITESTRING: + terminal_debug_writestring((const char*) regs->ebx); + break; + case SYS_TERMINAL_PUTCHAR: + terminal_putchar(regs->ebx); + break; + case SYS_TERMINAL_PUTENTRYAT: + terminal_putentryat(regs->ebx, regs->ecx, regs->edx, regs->esi); + break; + case SYS_TERMINAL_GETCOLOR: + eax = terminal_getcolor(); + break; + case SYS_TERMINAL_SETCOLOR: + terminal_setcolor(regs->ebx); + break; + case SYS_READ: + eax = read(regs->ebx, (void*) regs->ecx, regs->edx); + break; + case SYS_WRITE: + eax = write(regs->ebx, (void*) regs->ecx, regs->edx); + break; + default: + printf("nothing happened.\n"); + break; + } + + regs->eax = eax; + + return regs; +} diff --git a/kincl.h b/kincl.h deleted file mode 100644 index b74ff9b..0000000 --- a/kincl.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _KERNEL_INCLUDE_H -#define _KERNEL_INCLUDE_H - -#define KERNEL_VERSION "0.0.2a" - -#endif diff --git a/lib/espresso/kstring.c b/lib/espresso/kstring.c new file mode 100644 index 0000000..6a4b228 --- /dev/null +++ b/lib/espresso/kstring.c @@ -0,0 +1,58 @@ +#include +#include +#include + + +/* +A custom standard for strings for use in the Espresso kernel. +*/ + +struct kstring { + size_t s_len; + char* data; /* NOT null-terminated */ +}; + +/* +if the length of initial_data is more than initial_len, only initial_len bytes will be copied. +if the length of initial_data is less then initial_len, the rest of the bytes are zeroed. +if initial_data is null, no data is copied and the string in set to zero. +*/ +struct kstring* make_kstring(size_t initial_len, const char* initial_data) +{ + struct kstring* str = malloc(sizeof(struct kstring)); + + if (!str) + { + return NULL; + } + + str->s_len = initial_len; + str->data = malloc(initial_len); + + if (!str->data) + { + return NULL; + } + + memset(str->data, 0, initial_len); + + if (initial_data) + { + size_t slen = strlen(initial_data); + + if (slen < initial_len) + { + strncpy(str->data, initial_data, slen); + } + else if (slen > initial_len) + { + strncpy(str->data, initial_data, initial_len); + } + else + { + strcpy(str->data, initial_data); + } + } + + return str; +} diff --git a/lib/math/random.c b/lib/math/random.c new file mode 100644 index 0000000..0288585 --- /dev/null +++ b/lib/math/random.c @@ -0,0 +1,79 @@ +#include + +#include + + +/* + This code uses Xorshift (high speed, small) and PCG (Permuted Congruential Generator). + PCG may or may not be slightly slower than Xorshift. +*/ + +static uint32_t xorshift_state = 2463534242; + +static void srand_xorshift(uint32_t seed) +{ + xorshift_state = seed; +} + +static inline uint32_t rand_xorshift(void) +{ + uint32_t x = xorshift_state; + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + + return xorshift_state = x; +} + +static uint64_t state = 0x853c49e6748fea9bULL; +static uint64_t inc = 0xda3e39cb94b95bdbULL; + +static inline uint32_t rand_pcg32(void) +{ + uint64_t oldstate = state; + state = oldstate * 6364136223846793005ULL + (inc | 1); + uint32_t xorshifted = ((oldstate >> 18u) ^ oldstate) >> 27u; + uint32_t rot = oldstate >> 59u; + + return (xorshifted >> rot) | (xorshifted << ((-rot) & 31)); +} + +void seed_rand(uint32_t seed) +{ + srand_xorshift(seed); + state = seed * 6364136223846793005ULL + (seed | 1); +} + +uint32_t uirand(void) +{ + return rand_pcg32() ^ rand_xorshift(); +} + +/* get a number between 0 and max-1 */ +uint32_t uirand_range(uint32_t max) +{ + if (max == 0) + { + return 0; + } + + return uirand() % max; +} + +uint64_t ulrand(void) +{ + uint64_t hi = uirand(); + uint64_t lo = uirand(); + return (hi << 32) | lo; +} + +/* get a number between 0 and max-1 */ +uint64_t ulrand_range(uint64_t max) +{ + if (max == 0) + { + return 0; + } + + return ulrand() % max; +} diff --git a/lib/mm/heap.c b/lib/mm/heap.c index 461a879..651607a 100644 --- a/lib/mm/heap.c +++ b/lib/mm/heap.c @@ -111,7 +111,12 @@ void free(void* ptr) block_t* curr = free_list; while (curr && curr->next) { - if (curr->free && curr->next->free) + /*if (curr->free && curr->next->free) + { + curr->size += BLOCK_SIZE + curr->next->size; + curr->next = curr->next->next; + }*/ + if (curr->free && curr->next->free && (uint8_t*)curr + BLOCK_SIZE + curr->size == (uint8_t*)curr->next) { curr->size += BLOCK_SIZE + curr->next->size; curr->next = curr->next->next; diff --git a/lib/mm/pmm.c b/lib/mm/pmm.c index dcfdd88..3df4ea4 100644 --- a/lib/mm/pmm.c +++ b/lib/mm/pmm.c @@ -12,6 +12,10 @@ static size_t total_pages; #define BITMAP_CLEAR(i) (bitmap[(i) / 8] &= ~(1 << ((i) % 8))) #define BITMAP_TEST(i) (bitmap[(i) / 8] & (1 << ((i) % 8))) + +extern uint32_t __kernel_start; +extern uint32_t __kernel_end; + void pmm_init(multiboot_info_t* mb) { #ifdef _DEBUG @@ -45,6 +49,18 @@ void pmm_init(multiboot_info_t* mb) } } total_pages = MAX_PAGES; + + uintptr_t start = (uintptr_t)&__kernel_start; + uintptr_t end = (uintptr_t)&__kernel_end; + + start &= ~0xFFF; + end = (end + 0xFFF) & ~0xFFF; + + for (uintptr_t addr = start; addr < end; addr += 0x1000) + { + size_t idx = addr / 0x1000; + BITMAP_SET(idx); // Mark kernel pages as USED + } #ifdef _DEBUG printf("[ PMM ] Physical memory manager initialized\n"); @@ -55,6 +71,14 @@ void* pmm_alloc_page(void) { for (uint32_t i = 0; i < total_pages; ++i) { + void* page = (void*)(i * 4096); + + if ((uintptr_t)page >= (uintptr_t)&__kernel_start && + (uintptr_t)page < (uintptr_t)&__kernel_end) + { + printf("PMM allocating inside kernel at %x\n", page); + } + if (!BITMAP_TEST(i)) { BITMAP_SET(i); diff --git a/lib/printf.c b/lib/printf.c index c75a5ba..fd34fdc 100644 --- a/lib/printf.c +++ b/lib/printf.c @@ -4,6 +4,8 @@ #include #include +#include + #include static uint8_t color = 0xFF; diff --git a/lib/processes.c b/lib/processes.c index 668dede..9eca8e9 100644 --- a/lib/processes.c +++ b/lib/processes.c @@ -3,13 +3,18 @@ #include -int32_t next_id = 9; /* 0 through 8 are reserved for kernel operations */ +pid_t next_id = 1; /* start at 1 */ -int32_t make_process(char* name, char* group, elf_executable_t* exe) +pid_t make_process(char* name, char* group, elf_executable_t* exe) { + pid_t ret = (pid_t) 0; + if (!name || !group || !exe) { - return -1; + return ret; /* ret is already zero */ } - return 0; + + next_id++; + + return ret; } diff --git a/lib/scheduler.c b/lib/scheduler.c new file mode 100644 index 0000000..e225c2f --- /dev/null +++ b/lib/scheduler.c @@ -0,0 +1,76 @@ + +#include +#include + +#include + +#include + + +#define STACK_SIZE (8192) + +task_t* current_task = NULL; +task_t* task_list = NULL; +uint32_t next_pid = 1; + + +void init_scheduler(void) +{ + set_irq_handler(0, (irq_func_t) schedule); +} + +void scheduler(registers_t* boot_regs) +{ + task_t* task = malloc(sizeof(task_t)); + + task->id = next_pid++; + task->regs = boot_regs; + task->next = task; + + task_list = task; + current_task = task; +} + +registers_t* schedule(registers_t* regs) +{ + if (!current_task) + { + return regs; + } + + current_task->regs = regs; + + current_task = current_task->next; + + return current_task->regs; +} + +task_t* create_task(void (*entry)()) +{ + task_t* task = malloc(sizeof(task_t)); + uint32_t* stack = malloc(STACK_SIZE); + + uint32_t stack_top = (uint32_t)stack + 4096; + + stack_top -= sizeof(registers_t); + registers_t* regs = (registers_t*)stack_top; + + memset(regs, 0, sizeof(registers_t)); + + regs->eip = (uint32_t) entry; + regs->cs = 0x08; /* kernel code */ + regs->ds = 0x10; + regs->es = 0x10; + regs->fs = 0x10; + regs->gs = 0x10; + regs->eflags = 0x202; /* IF = 1 */ + + task->id = next_pid++; + task->regs = regs; + + /* insert into circular list */ + task->next = task_list->next; + task_list->next = task; + + return task; +} diff --git a/lib/stdio.c b/lib/stdio.c index 7600b19..1587e7a 100644 --- a/lib/stdio.c +++ b/lib/stdio.c @@ -2,8 +2,45 @@ #include #include +#include +#include + +#include + #include +int write(uint32_t fd, void* data, size_t len) +{ + if (fd == STDOUT) + { + print_uint((uint32_t) len); + terminal_write((char*) data, len); + } + else + { + return -1; + } + + return 0; +} + +int read(uint32_t fd, void* data, size_t max_len) +{ + int rv = 0; + + if (fd == STDIN) + { + char* sptr = (char*) data; /* this really shouldn't be needed... */ + sptr = gets_new(&rv); + } + else + { + return -1; + } + + return rv; +} + extern bool ps2keyboard_initialized; char getchar(void) @@ -31,40 +68,33 @@ char* gets(void) return kbd_gets(); } - - -/*char* fgets(char* buf, int n, FILE file) +char* gets_new(int* num) { - if (!buf || n <= 1 || file < 1) + char* __s = malloc(256); + + memset(__s, 0, 256); + + ssize_t n = tty_read_active(__s, 255); + + *num = (int) n; + + return __s; +} + +int getstr(char* dest) +{ + int i = 0; + char* p = gets_new(&i); + + if (i != 0) { - return NULL; + return -1; } - int total_read = 0; - char c; + strcpy(dest, p); +} - while (total_read < n - 1) - { - int bytes = 0*//*read_file(file, &c, 1)*/; - - /*if (bytes <= 0) - { - break; *//* EOF or error */ - /*} - - buf[total_read++] = c; - - if (c == '\n') - { - break; *//* Stop at newline */ - /*} - } - - if (total_read == 0) - { - return NULL; *//* Nothing read (e.g. EOF) */ - /*} - - buf[total_read] = '\0'; - return buf; -}*/ +void putc(char c) +{ + syscall1(SYS_TERMINAL_PUTCHAR, c); +} diff --git a/lib/string.c b/lib/string.c index 37e2517..147cf8e 100644 --- a/lib/string.c +++ b/lib/string.c @@ -1,10 +1,12 @@ #include #include -#include #include +#ifdef DEBUG_USE_SSE2 +#include extern int32_t sse_initialized; +#endif size_t strlen(const char* str) { @@ -76,10 +78,12 @@ char* strcpy(char *dst, const char *src) char* strncpy(char *dest, const char *src, uint32_t n) { +#ifdef DEBUG_USE_SSE2 if (sse_initialized > 0) { return sse2_strncpy(dest, src, n); } +#endif uint32_t i = 0; for (; i < n && src[i]; ++i) @@ -217,10 +221,12 @@ void* memset(void* dst, int c, size_t n) void* memcpy(void *dst, const void *src, uint32_t n) { +#ifdef DEBUG_USE_SSE2 if (sse_initialized > 1) { return sse2_memcpy(dst, src, n); } +#endif char *d = dst; const char *s = src; @@ -234,8 +240,8 @@ void* memcpy(void *dst, const void *src, uint32_t n) int32_t memcmp(const void *s1, const void *s2, size_t n) { - const uint8_t *p1 = (const uint8_t *)s1; - const uint8_t *p2 = (const uint8_t *)s2; + const uint8_t *p1 = (const uint8_t*) s1; + const uint8_t *p2 = (const uint8_t*) s2; /*printf("p1: %i, p2: %i\n", (int32_t)*p1, (int32_t)*p2);*/ @@ -252,10 +258,12 @@ int32_t memcmp(const void *s1, const void *s2, size_t n) void* memclr(void* m_start, size_t m_count) { +#ifdef DEBUG_USE_SSE2 if (sse_initialized > 1) { return memclr_sse2(m_start, m_count); } +#endif return memset(m_start, '\0', (uint32_t)m_count); } @@ -451,3 +459,36 @@ double atof(const char *str) return sign * (res + frac / frac_div); } +char* strnlstrip(const char* s) +{ + if (!s) + { + return NULL; + } + + char* new = strdup(s); + if (!new) + { + return NULL; + } + + size_t len = strlen(new); + + while (len > 0 && (new[len-1] == '\n' || new[len-1] == '\r')) + { + new[len-1] = '\0'; + len--; + } + + return new; +} + +void strlnstripip(char* s) +{ + size_t len = strlen(s); + + if (len > 0 && s[len-1] == '\n') + { + s[len-1] = '\0'; + } +} diff --git a/lib/sync.c b/lib/sync.c new file mode 100644 index 0000000..2fc8781 --- /dev/null +++ b/lib/sync.c @@ -0,0 +1,40 @@ + + +#include + + +void spinlock_init(spinlock_t* lock) +{ + lock->locked = 0; +} + +static inline int atomic_xchg(volatile int* addr, int newval) +{ + int result; + + asm volatile ( + "xchg %0, %1" + : "=r"(result), "+m"(*addr) + : "0"(newval) + : "memory" + ); + + return result; +} + +void spin_lock(spinlock_t* lock) +{ + while (atomic_xchg(&lock->locked, 1)) + { + while (lock->locked) + { + asm volatile("pause"); + } + } +} + +void spin_unlock(spinlock_t* lock) +{ + __atomic_clear(&lock->locked, __ATOMIC_RELEASE); +} + diff --git a/lib/vector_extensions/sse.c b/lib/vector_extensions/sse.c index 7ab88b5..8a3da17 100644 --- a/lib/vector_extensions/sse.c +++ b/lib/vector_extensions/sse.c @@ -1,3 +1,5 @@ +#ifdef DEBUG_USE_SSE2 + #include #include @@ -248,3 +250,5 @@ void* memclr_sse2(void *m_start, size_t m_count) return m_start; } + +#endif diff --git a/libc/include/stdio.h b/libc/include/stdio.h new file mode 100644 index 0000000..26d4d14 --- /dev/null +++ b/libc/include/stdio.h @@ -0,0 +1,9 @@ +#ifndef LIBC_STDIO_H +#define LIBC_STDIO_H + +int writestring(const char* __s); +void writechar(char __c); + +int getstring(char* __str); + +#endif diff --git a/libc/include/string.h b/libc/include/string.h new file mode 100644 index 0000000..07aef7c --- /dev/null +++ b/libc/include/string.h @@ -0,0 +1,19 @@ +#ifndef _LIBC_STRING_H +#define _LIBC_STRING_H + +#include +#include + +size_t strlen(const char* str); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +char* strcpy(char *dst, const char *src); +char* strncpy(char *dest, const char *src, uint32_t n); +char* strcat(char *dest, const char *src); +/*char* strdup(const char* s);*/ + +int memcmp(const void *s1, const void *s2, size_t n); +void* memcpy(void *dst, const void *src, uint32_t n); +void* memset(void* dst, int c, size_t n); + +#endif diff --git a/libc/stdio.c b/libc/stdio.c new file mode 100644 index 0000000..4aa457c --- /dev/null +++ b/libc/stdio.c @@ -0,0 +1,22 @@ +#include "include/string.h" + +#include "../syscall.h" + +#include "include/stdio.h" + + +int writestring(const char* __s) +{ + /*syscall1(SYS_TERMINAL_WRITESTRING, __s);*/ + return syscall3(SYS_WRITE, 1, __s, strlen(__s)); +} + +void writechar(char __c) +{ + syscall1(SYS_TERMINAL_PUTCHAR, __c); +} + +int getstring(char* __str) +{ + return syscall3(SYS_READ, 0, __str, 0); +} diff --git a/libc/string.c b/libc/string.c new file mode 100644 index 0000000..ef51150 --- /dev/null +++ b/libc/string.c @@ -0,0 +1,125 @@ +#include +#include + +#include "include/string.h" + +size_t strlen(const char* str) +{ + size_t len = 0; + while (str[len]) + { + len++; + } + return len; +} + +int strcmp(const char *s1, const char *s2) +{ + while (*s1 && (*s1 == *s2)) + { + s1++; + s2++; + } + return (unsigned char)*s1 - (unsigned char)*s2; +} + +int strncmp(const char *s1, const char *s2, size_t n) +{ + while (n--) + { + unsigned char c1 = (unsigned char)*s1++; + unsigned char c2 = (unsigned char)*s2++; + if (c1 != c2) + { + return c1 - c2; + } + if (c1 == '\0') + { + break; + } + } + return 0; +} + +char* strcpy(char *dst, const char *src) +{ + char *ret = dst; + while ((*dst++ = *src++) != 0); + return ret; +} + +char* strncpy(char *dest, const char *src, uint32_t n) +{ + uint32_t i = 0; + for (; i < n && src[i]; ++i) + { + dest[i] = src[i]; + } + + for (; i < n; ++i) + { + dest[i] = '\0'; + } + + return dest; +} + +char* strcat(char *dest, const char *src) +{ + char *end = dest + strlen(dest); + while (*src) + { + *end++ = *src++; + } + + *end = '\0'; + return dest; +} + + +/*char* strdup(const char* s) +{ + if (!s) + { + return NULL; + } + + size_t len = strlen(s); + char* copy = (char*)malloc(len + 1); + + if (!copy) + { + return NULL; + } + + memcpy(copy, s, len); + copy[len] = '\0'; + + return copy; +}*/ + +void* memset(void* dst, int c, size_t n) +{ + unsigned char* temp = (unsigned char*) dst; + unsigned char val = (unsigned char) c; + + for (size_t i = 0; i < n; i++) + { + temp[i] = val; + } + + return dst; +} + + +void* memcpy(void *dst, const void *src, uint32_t n) +{ + char *d = dst; + const char *s = src; + while (n--) + { + *d++ = *s++; + } + + return dst; +} diff --git a/syscall.h b/syscall.h new file mode 100644 index 0000000..5bc9635 --- /dev/null +++ b/syscall.h @@ -0,0 +1,110 @@ +#ifndef _ESPRESSO_SYSCALL_H +#define _ESPRESSO_SYSCALL_H + +/* +Use this file to use syscalls in Espresso. +do not use kernel/syscall.h, because it has some defiitions which are not used/needed here. +*/ + +#define SYSCALL_INT 0x30 + +enum { + SYS_MAP_PAGE = 0, /* void map_page(void* phys_addr, void* virt_addr); */ + SYS_PMM_ALLOC_PAGE, /* void* pmm_alloc_page(void); */ + SYS_PMM_FREE_PAGE, /* void pmm_free_page(void* addr); */ + SYS_SERIAL_WRITE, /* void serial_write(char a); */ + SYS_SERIAL_READ, /* char serial_read(void); */ + SYS_SERIAL_PUTS, /* void serial_puts(const char* s); */ + SYS_USE_SERIAL, /* bool use_serial(void); */ + SYS_TERMINAL_SCROLL, /* void terminal_scroll(void); */ + SYS_TERMINAL_CLEAR, /* void terminal_clear(void); */ + SYS_TERMINAL_SET_CURSOR, /* void terminal_set_cursor(uint16_t row, uint16_t column); */ + SYS_TERMINAL_GET_CURSOR, /* void terminal_get_cursor(int* row, int* column); */ + SYS_TERMINAL_WRITE, /* void terminal_write(const char* data, size_t size); */ + SYS_TERMINAL_WRITESTRING, /* void terminal_writestring(const char* data) */ + SYS_TERMINAL_DEBUG_WRITESTRING, /* void terminal_debug_writestring(const char* data); */ + SYS_TERMINAL_PUTCHAR, /* void terminal_putchar(char c); */ + SYS_TERMINAL_PUTENTRYAT, /* void terminal_putentryat(unsigned char c, uint8_t color, size_t x, size_t y); */ + SYS_TERMINAL_GETCOLOR, /* uint8_t terminal_getcolor(void); */ + SYS_TERMINAL_SETCOLOR, /* void terminal_setcolor(uint8_t color); */ + SYS_READ, /* int read(uint32_t fd, void* data, size_t max_len); */ + SYS_WRITE, /* int write(uint32_t fd, void* data, size_t len); */ + __ENUM_END_MARKER__, +}; + + +#define syscall0(num) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num) \ + : "memory" \ + ); \ + ret; \ +}) + +/* syscall 1 */ +#define syscall1(num, a) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall2(num, a, b) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall3(num, a, b, c) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall4(num, a, b, c, d) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c), "S"(d) \ + : "memory" \ + ); \ + ret; \ +}) + +#define syscall5(num, a, b, c, d, e) ({ \ + int ret; \ + asm volatile ( \ + "int %1" \ + : "=a"(ret) \ + : "i"(SYSCALL_INT), "a"(num), "b"(a), "c"(b), "d"(c), "S"(d), "D"(e) \ + : "memory" \ + ); \ + ret; \ +}) + +/* some macros for commonly used functions */ +#define syscall_terminal_writestring(ptr) syscall1(SYS_TERMINAL_WRITESTRING, ptr); +#define syscall_terminal_putchar(chr) syscall1(SYS_TERMINAL_PUTCHAR, chr); +#define syscall_map_page(phys, virt) syscall2(SYS_MAP_PAGE, phys, virt); +#define syscall_pmm_alloc_page() syscall0(SYS_PMM_ALLOC_PAGE); +#define syscall_pmm_free_page(addr) syscall1(SYS_PMM_FREE_PAGE, addr); + +#endif diff --git a/usefull_gcc_stuff.txt.junk b/usefull_gcc_stuff.txt.junk new file mode 100644 index 0000000..df81087 --- /dev/null +++ b/usefull_gcc_stuff.txt.junk @@ -0,0 +1,3 @@ +https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html#index-_005f_005fbuiltin_005fprefetch +https://gcc.gnu.org/onlinedocs/gcc/Bit-Operation-Builtins.html + diff --git a/user/hello.elf b/user/hello.elf new file mode 100755 index 0000000000000000000000000000000000000000..d049ca8f57268ce8e191882f6930afdb49571456 GIT binary patch literal 2128 zcma)8ZD?Cn7(Ta6w`&PaR&{O;BlyyER{k_=BimP4)t2RUL2FmNZnj5 zOmu8m+~IGngIZ}fxoqTRmRqboSd73~m&$R)MZss;CuRF-(H6y>ta`zMM6QXrFj*UOC z0wZ5zx^R6(uD{yEoEx{u<;Z+Zuh)YnuNe6X(-n(XiepWSZ;E7(cjmfUM!pbX$p&eC z>}a_%AMBvyo;i3;2fKx=K4C>RcNgHD?Pe1*L*Nyq@|GKqB4IwGBpu^*ZIyhTm5iq? zC-*^{7JtIYdae|h`yMijfUMdfj5T7f6l3-^v6I0Y+!j8c!EMQk$QBIk!fYw`JKk4_ zR+SAdO9uC2YFYSnYzyA-^aCGV)^9tWz(Uy>3M`aD%Vv4fouzsVesK~gzQ9pGzkn28 z;M;)(-t6bwI$)#;upL^i9=eooGCg4NAnI*Kg4qA7RcZbzrE8W&Vn&VfFu6T%Mf}AV zC6oJUo*~H`!93lCphz~i?kxm-Z@mW*A=ZjBY(;Eol@e(aMd0?+JeXBHf}>Hc2E6Lf zCR4ElPoqQaCDY8wm5;=(`9PM+$gKK6OKP@A%@(OSbwZhcfDj~GWW<^pAQbqPmv6Tf z!H6v_qdHryiE6*@jBe0+4gUpc4hSzSwI&MBIz=d_HPP)J1rp23yyh>QDRCvdl3cJXo8^WYDGE{?+Pe-HOHT9CD|^RS=7-w#Xi8Z6!ULs%H$3&45kKj!-1gyqnG&cy}T zR=u}@547mN3;YoHv@X(Px|-F)apr8AcuAzDoPqfC3`?tNG8eRzuEvuwjZI^7^=J+c ziiyW`$LGY;P$r(9b}Zte(X-iXG^@unouslVOe~dQJI6$bARwwHVtNcFlc1qj)eK|d z>`YpZorTpk$0ofuUA?HYur?)v!gLUEXt1RJ-420?)#Iz_?B@jRs1Fafk&oKL==6?j zn$d^q3OKYUUh_gi7$BZ^BI&zJKOe7=&+DY+wI1-Ehl9S+q(vQ{YIYAgzI8h-i9|o# UL5>zdI?t`VcKl!P)PL~)0jisaYXATM literal 0 HcmV?d00001 diff --git a/user/test.c b/user/test.c new file mode 100644 index 0000000..419a4ec --- /dev/null +++ b/user/test.c @@ -0,0 +1,75 @@ + +#include "../libc/include/stdio.h" +#include "../libc/include/string.h" + +/*extern void writestring(const char* __s); +extern char* getstring(void);*/ + +void print_uint(uint32_t value) +{ + char buffer[11]; + int i = 0; + + do + { + buffer[i++] = '0' + (value % 10); + value /= 10; + } while (value > 0); + + while (i--) + { + writechar(buffer[i]); + } +} + +int main(void) +{ + while (1) + { + writestring("command: "); + + char* istr; + + int rv = getstring(istr); + + if (!istr) + { + writestring("\nERROR: getstring returned NULL\n"); + break; + } + + if (rv != 0) + { + writestring("\nERROR: getstring did not return 0\n"); + break; + } + + size_t len = strlen(istr); + + if (len > 0 && istr[len - 1] == '\n') + { + istr[len - 1] = '\0'; + } + + + writestring("you entered: "); + writestring(istr); + + writestring(" ASCII -> "); + + for (size_t n = 0; n < (len + 1); n++) + { + print_uint(istr[n]); + writechar(' '); + } + + writechar('\n'); + + if (strcmp(istr, "exit") == 0) + { + return 0; + } + } + + return 0; +}