diff --git a/Makefile b/Makefile index 0ddd307..7088805 100644 --- a/Makefile +++ b/Makefile @@ -32,7 +32,7 @@ LDFLAGS = -m elf_x86_64 -nostdlib -static -pie --no-dynamic-linker \ NASMFLAGS = -f elf64 # Limine Version -LIMINE_VERSION = 7.0.0 +LIMINE_VERSION = 10.8.2 LIMINE_URL_BASE = https://github.com/limine-bootloader/limine/raw/v$(LIMINE_VERSION) .PHONY: all clean run limine-setup @@ -86,21 +86,21 @@ $(KERNEL_ELF): $(OBJ_FILES) $(MAKE) -C $(SRC_DIR)/userland # Create ISO -$(ISO_IMAGE): $(KERNEL_ELF) limine.cfg limine-setup +$(ISO_IMAGE): $(KERNEL_ELF) limine.conf limine-setup rm -rf $(ISO_DIR) mkdir -p $(ISO_DIR) mkdir -p $(ISO_DIR)/EFI/BOOT # Copy Kernel and Config cp $(KERNEL_ELF) $(ISO_DIR)/ - # Build ISO limine.cfg natively with modules - cp limine.cfg $(ISO_DIR)/ + # Build ISO limine.conf natively with modules + cp limine.conf $(ISO_DIR)/ mkdir -p $(ISO_DIR)/bin @for f in $(SRC_DIR)/userland/*.elf; do \ if [ -f "$$f" ]; then \ basename=$$(basename "$$f"); \ cp "$$f" $(ISO_DIR)/bin/; \ - echo " MODULE_PATH=boot:///bin/$$basename" >> $(ISO_DIR)/limine.cfg; \ + echo " module_path: boot():/bin/$$basename" >> $(ISO_DIR)/limine.conf; \ fi \ done diff --git a/boredos.iso b/boredos.iso index ee18d66..85729bc 100644 Binary files a/boredos.iso and b/boredos.iso differ diff --git a/build/about.o b/build/about.o index 149b7d2..7185caa 100644 Binary files a/build/about.o and b/build/about.o differ diff --git a/build/boredos.elf b/build/boredos.elf index 518e8eb..ce23f3c 100755 Binary files a/build/boredos.elf and b/build/boredos.elf differ diff --git a/build/cli_apps/boredver.o b/build/cli_apps/boredver.o index f659202..f12cb06 100644 Binary files a/build/cli_apps/boredver.o and b/build/cli_apps/boredver.o differ diff --git a/build/cli_apps/cli_utils.o b/build/cli_apps/cli_utils.o index 1c8317b..e4ac893 100644 Binary files a/build/cli_apps/cli_utils.o and b/build/cli_apps/cli_utils.o differ diff --git a/build/cli_apps/txtedit.o b/build/cli_apps/txtedit.o index 0ecaf99..7a89178 100644 Binary files a/build/cli_apps/txtedit.o and b/build/cli_apps/txtedit.o differ diff --git a/build/cmd.o b/build/cmd.o index 1562ad5..dbe7068 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/control_panel.o b/build/control_panel.o index cfcce27..e0cb1aa 100644 Binary files a/build/control_panel.o and b/build/control_panel.o differ diff --git a/build/explorer.o b/build/explorer.o index 607d9c9..c186bb2 100644 Binary files a/build/explorer.o and b/build/explorer.o differ diff --git a/build/icmp.o b/build/icmp.o index a58dbf3..8886576 100644 Binary files a/build/icmp.o and b/build/icmp.o differ diff --git a/build/idt.o b/build/idt.o index 243c75e..b6d1e78 100644 Binary files a/build/idt.o and b/build/idt.o differ diff --git a/build/main.o b/build/main.o index 9c77b15..433fb1a 100644 Binary files a/build/main.o and b/build/main.o differ diff --git a/build/minesweeper.o b/build/minesweeper.o index 06005fb..c8b8242 100644 Binary files a/build/minesweeper.o and b/build/minesweeper.o differ diff --git a/build/notepad.o b/build/notepad.o deleted file mode 100644 index 609ec59..0000000 Binary files a/build/notepad.o and /dev/null differ diff --git a/build/paint.o b/build/paint.o index 7f01810..a94b289 100644 Binary files a/build/paint.o and b/build/paint.o differ diff --git a/build/ps2.o b/build/ps2.o index 0dcd680..f1ca8f1 100644 Binary files a/build/ps2.o and b/build/ps2.o differ diff --git a/build/vm.o b/build/vm.o index 0b23d06..7e51aba 100644 Binary files a/build/vm.o and b/build/vm.o differ diff --git a/build/wallpaper.o b/build/wallpaper.o index 132dc0c..1b0abc7 100644 Binary files a/build/wallpaper.o and b/build/wallpaper.o differ diff --git a/build/wm.o b/build/wm.o index 9703057..43ea6b2 100644 Binary files a/build/wm.o and b/build/wm.o differ diff --git a/disk.img b/disk.img index b0bde30..82d79bc 100644 Binary files a/disk.img and b/disk.img differ diff --git a/iso_root/EFI/BOOT/BOOTIA32.EFI b/iso_root/EFI/BOOT/BOOTIA32.EFI index 27d59d4..93716eb 100644 Binary files a/iso_root/EFI/BOOT/BOOTIA32.EFI and b/iso_root/EFI/BOOT/BOOTIA32.EFI differ diff --git a/iso_root/EFI/BOOT/BOOTX64.EFI b/iso_root/EFI/BOOT/BOOTX64.EFI index a5a4883..7b1fc18 100644 Binary files a/iso_root/EFI/BOOT/BOOTX64.EFI and b/iso_root/EFI/BOOT/BOOTX64.EFI differ diff --git a/iso_root/bin/calculator.elf b/iso_root/bin/calculator.elf index 96cd3a9..a9e333b 100755 Binary files a/iso_root/bin/calculator.elf and b/iso_root/bin/calculator.elf differ diff --git a/iso_root/bin/crash.elf b/iso_root/bin/crash.elf index c3b4e17..b53e28c 100755 Binary files a/iso_root/bin/crash.elf and b/iso_root/bin/crash.elf differ diff --git a/iso_root/bin/hello.elf b/iso_root/bin/hello.elf index b529f97..2a76bbc 100755 Binary files a/iso_root/bin/hello.elf and b/iso_root/bin/hello.elf differ diff --git a/iso_root/bin/notepad.elf b/iso_root/bin/notepad.elf new file mode 100755 index 0000000..6a39864 Binary files /dev/null and b/iso_root/bin/notepad.elf differ diff --git a/iso_root/boredos.elf b/iso_root/boredos.elf index 518e8eb..ce23f3c 100755 Binary files a/iso_root/boredos.elf and b/iso_root/boredos.elf differ diff --git a/iso_root/limine-bios-cd.bin b/iso_root/limine-bios-cd.bin index 645bf55..2d1601a 100644 Binary files a/iso_root/limine-bios-cd.bin and b/iso_root/limine-bios-cd.bin differ diff --git a/iso_root/limine-bios.sys b/iso_root/limine-bios.sys index 6d95511..8a59e13 100644 Binary files a/iso_root/limine-bios.sys and b/iso_root/limine-bios.sys differ diff --git a/iso_root/limine-uefi-cd.bin b/iso_root/limine-uefi-cd.bin index 873b059..f4420a5 100644 Binary files a/iso_root/limine-uefi-cd.bin and b/iso_root/limine-uefi-cd.bin differ diff --git a/iso_root/limine.cfg b/iso_root/limine.cfg deleted file mode 100644 index fc0183c..0000000 --- a/iso_root/limine.cfg +++ /dev/null @@ -1,11 +0,0 @@ -TIMEOUT=3 - -:BoredOS - PROTOCOL=limine - - KERNEL_PATH=boot:///boredos.elf - #FRAMEBUFFER_WIDTH=1280 - #FRAMEBUFFER_HEIGHT=720 - MODULE_PATH=boot:///bin/calculator.elf - MODULE_PATH=boot:///bin/crash.elf - MODULE_PATH=boot:///bin/hello.elf diff --git a/iso_root/limine.conf b/iso_root/limine.conf new file mode 100644 index 0000000..9f6665f --- /dev/null +++ b/iso_root/limine.conf @@ -0,0 +1,11 @@ +timeout: 3 + +/BoredOS + protocol: limine + + kernel_path: boot():/boredos.elf + #resolution: 1280x720 + module_path: boot():/bin/calculator.elf + module_path: boot():/bin/crash.elf + module_path: boot():/bin/hello.elf + module_path: boot():/bin/notepad.elf diff --git a/limine b/limine index efd130d..38ff2c8 160000 --- a/limine +++ b/limine @@ -1 +1 @@ -Subproject commit efd130dbb649983cd3a7667b6cfa4f6e5d8a3da6 +Subproject commit 38ff2c855aabb92e4cfa2cc7ef0c8af665ecba94 diff --git a/limine.cfg b/limine.cfg deleted file mode 100644 index daa3ef0..0000000 --- a/limine.cfg +++ /dev/null @@ -1,8 +0,0 @@ -TIMEOUT=3 - -:BoredOS - PROTOCOL=limine - - KERNEL_PATH=boot:///boredos.elf - #FRAMEBUFFER_WIDTH=1280 - #FRAMEBUFFER_HEIGHT=720 diff --git a/limine.conf b/limine.conf new file mode 100644 index 0000000..7cba8f4 --- /dev/null +++ b/limine.conf @@ -0,0 +1,7 @@ +timeout: 3 + +/BoredOS + protocol: limine + + kernel_path: boot():/boredos.elf + #resolution: 1280x720 diff --git a/src/kernel/cli_apps/txtedit.c b/src/kernel/cli_apps/txtedit.c index 1155c0c..d4ba19b 100644 --- a/src/kernel/cli_apps/txtedit.c +++ b/src/kernel/cli_apps/txtedit.c @@ -8,7 +8,6 @@ extern void editor_init(void); extern Window win_editor; extern Window win_explorer; extern Window win_cmd; -extern Window win_notepad; void cli_cmd_txtedit(char *args) { // Parse the file path argument @@ -50,7 +49,6 @@ void cli_cmd_txtedit(char *args) { int max_z = 0; if (win_explorer.z_index > max_z) max_z = win_explorer.z_index; if (win_cmd.z_index > max_z) max_z = win_cmd.z_index; - if (win_notepad.z_index > max_z) max_z = win_notepad.z_index; win_editor.z_index = max_z + 1; cli_write("Opening: "); diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index 122c655..00c4dd7 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -3,7 +3,7 @@ #include "wm.h" #include "io.h" #include "rtc.h" -#include "notepad.h" + #include "fat32.h" #include "disk.h" #include "cli_apps/cli_apps.h" @@ -554,7 +554,6 @@ static void internal_cmd_txtedit(char *args) { // Make editor window visible and focused, bring to front extern Window win_explorer; extern Window win_cmd; - extern Window win_notepad; win_editor.visible = true; win_editor.focused = true; @@ -563,7 +562,6 @@ static void internal_cmd_txtedit(char *args) { int max_z = 0; if (win_explorer.z_index > max_z) max_z = win_explorer.z_index; if (win_cmd.z_index > max_z) max_z = win_cmd.z_index; - if (win_notepad.z_index > max_z) max_z = win_notepad.z_index; win_editor.z_index = max_z + 1; cmd_write("Opening: "); @@ -646,7 +644,7 @@ void cmd_exec_elf(char *args) { } cmd_is_waiting_for_process = true; - process_create_elf(full_exec_path); + process_create_elf(full_exec_path, args); } // Public API for syscall exit @@ -1176,7 +1174,7 @@ static void cmd_exec_single(char *cmd) { if (fh) { fat32_close(fh); cmd_is_waiting_for_process = true; - process_create_elf(search_path); + process_create_elf(search_path, args); return; } } @@ -1197,7 +1195,7 @@ static void cmd_exec_single(char *cmd) { if (fh) { fat32_close(fh); cmd_is_waiting_for_process = true; - process_create_elf(search_path); + process_create_elf(search_path, args); return; } } diff --git a/src/kernel/elf.c b/src/kernel/elf.c index 6521827..f05461c 100644 --- a/src/kernel/elf.c +++ b/src/kernel/elf.c @@ -59,10 +59,6 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) { return 0; } - serial_write("[ELF] Number of program headers: "); - print_hex(ehdr.e_phnum); - serial_write("\n"); - // Iterate Over Program Headers for (int i = 0; i < ehdr.e_phnum; i++) { fat32_seek(file, ehdr.e_phoff + (i * ehdr.e_phentsize), 0); @@ -72,10 +68,6 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) { continue; } - serial_write("[ELF] Header type parsed: "); - print_hex(phdr.p_type); - serial_write("\n"); - // Only load segments with type PT_LOAD if (phdr.p_type == PT_LOAD) { uint64_t p_vaddr = phdr.p_vaddr; @@ -83,10 +75,6 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) { uint64_t p_filesz = phdr.p_filesz; uint64_t p_offset = phdr.p_offset; - serial_write("[ELF] Loaded PT_LOAD segment vaddr="); - print_hex(p_vaddr); - serial_write("\n"); - if (p_memsz == 0) continue; // Calculate page-aligned boundaries @@ -103,36 +91,32 @@ uint64_t elf_load(const char *path, uint64_t user_pml4) { fat32_close(file); return 0; } - // Determine Flags - uint64_t flags = 0x07; // Present, RW, User + + // Map page to user space (Present, RW, User) + paging_map_page(user_pml4, vaddr, v2p((uint64_t)phys), 0x07); - paging_map_page(user_pml4, vaddr, v2p((uint64_t)phys), flags); - - // Initialize page memory + // Zero out the entire page (handles BSS and padding) uint8_t* dest = (uint8_t*)phys; - for (int j=0; j<4096; j++) dest[j] = 0; // zero memory (handles BSS) + for (int j=0; j<4096; j++) dest[j] = 0; - // If loading from file - if (p_filesz > 0) { - uint64_t copy_start_offset = 0; - uint64_t file_seek_pos = p_offset; - uint64_t bytes_to_copy = 4096; - - if (p == 0) { - copy_start_offset = align_offset; - bytes_to_copy = 4096 - align_offset; - } else { - file_seek_pos += (p * 4096) - align_offset; - } + // Copy data from file if available for this page + uint64_t page_vaddr_start = vaddr; + uint64_t page_vaddr_end = vaddr + 4096; - if (bytes_to_copy > p_filesz) { - bytes_to_copy = p_filesz; - } - if (bytes_to_copy > 0) { - fat32_seek(file, file_seek_pos, 0); - fat32_read(file, dest + copy_start_offset, bytes_to_copy); - p_filesz -= bytes_to_copy; - } + // What part of the segment (p_vaddr to p_vaddr + p_filesz) overlaps this page? + uint64_t overlap_vaddr_start = p_vaddr; + if (page_vaddr_start > overlap_vaddr_start) overlap_vaddr_start = page_vaddr_start; + + uint64_t overlap_vaddr_end = p_vaddr + p_filesz; + if (page_vaddr_end < overlap_vaddr_end) overlap_vaddr_end = page_vaddr_end; + + if (overlap_vaddr_start < overlap_vaddr_end) { + uint64_t copy_size = overlap_vaddr_end - overlap_vaddr_start; + uint64_t dest_offset = overlap_vaddr_start - page_vaddr_start; + uint64_t file_offset = p_offset + (overlap_vaddr_start - p_vaddr); + + fat32_seek(file, file_offset, 0); + fat32_read(file, dest + dest_offset, (uint32_t)copy_size); } } } diff --git a/src/kernel/explorer.c b/src/kernel/explorer.c index dd1108a..8b70277 100644 --- a/src/kernel/explorer.c +++ b/src/kernel/explorer.c @@ -7,7 +7,7 @@ #include "editor.h" #include "markdown.h" #include "cmd.h" -#include "notepad.h" + #include "process.h" #include "minesweeper.h" #include "viewer.h" @@ -817,7 +817,7 @@ static void explorer_open_target(const char *path) { explorer_open_directory(path); } else { if (explorer_str_ends_with(path, ".elf")) { - process_create_elf(path); + process_create_elf(path, NULL); } else if (explorer_is_markdown_file(path)) { wm_bring_to_front(&win_markdown); markdown_open_file(path); @@ -853,9 +853,9 @@ static void explorer_open_item(Window *win, int index) { if (explorer_str_ends_with(state->items[index].name, ".shortcut")) { Window *target = NULL; if (explorer_strcmp(state->items[index].name, "Notepad.shortcut") == 0) { - target = &win_notepad; + process_create_elf("/bin/notepad.elf", NULL); return; } else if (explorer_strcmp(state->items[index].name, "Calculator.shortcut") == 0) { - process_create_elf("/bin/calculator.elf"); return; + process_create_elf("/bin/calculator.elf", NULL); return; } else if (explorer_strcmp(state->items[index].name, "Terminal.shortcut") == 0) { target = &win_cmd; cmd_reset(); } else if (explorer_strcmp(state->items[index].name, "Minesweeper.shortcut") == 0) { @@ -1785,7 +1785,6 @@ static void explorer_handle_file_context_menu_click(Window *win, int x, int y) { int max_z = 0; for (int i = 0; i < explorer_win_count; i++) if (explorer_wins[i]->z_index > max_z) max_z = explorer_wins[i]->z_index; if (win_cmd.z_index > max_z) max_z = win_cmd.z_index; - if (win_notepad.z_index > max_z) max_z = win_notepad.z_index; if (win_editor.z_index > max_z) max_z = win_editor.z_index; if (win_markdown.z_index > max_z) max_z = win_markdown.z_index; if (win_control_panel.z_index > max_z) max_z = win_control_panel.z_index; diff --git a/src/kernel/gdt_asm.asm b/src/kernel/gdt_asm.asm index 08777a9..4357a0b 100644 --- a/src/kernel/gdt_asm.asm +++ b/src/kernel/gdt_asm.asm @@ -6,7 +6,7 @@ section .text gdt_flush: lgdt [rdi] ; Load GDT from the pointer passed in RDI - mov ax, 0x10 ; 0x10 is our offset in the GDT to our data segment + mov ax, 0x10 ; 0x10 is the offset in the GDT to data segment mov ds, ax mov es, ax mov fs, ax @@ -14,7 +14,7 @@ gdt_flush: mov ss, ax ; Far jump to update CS - push 0x08 ; 0x08 is our offset to the code segment + push 0x08 ; 0x08 is the offset to the code segment lea rax, [rel .flush] push rax retfq @@ -23,6 +23,6 @@ gdt_flush: ret tss_flush: - mov ax, 0x28 ; 0x28 is our offset in the GDT to the TSS + mov ax, 0x28 ; 0x28 is the offset in the GDT to the TSS ltr ax ret diff --git a/src/kernel/gui_ipc.h b/src/kernel/gui_ipc.h index a662e1c..1d2a041 100644 --- a/src/kernel/gui_ipc.h +++ b/src/kernel/gui_ipc.h @@ -13,6 +13,7 @@ #define GUI_EVENT_CLICK 2 #define GUI_EVENT_RIGHT_CLICK 3 #define GUI_EVENT_CLOSE 4 +#define GUI_EVENT_KEY 5 typedef struct { int type; diff --git a/src/kernel/notepad.c b/src/kernel/notepad.c deleted file mode 100644 index a71dc9f..0000000 --- a/src/kernel/notepad.c +++ /dev/null @@ -1,230 +0,0 @@ -#include "notepad.h" -#include "graphics.h" -#include - -Window win_notepad; -static int notepad_scroll_line = 0; - -static void notepad_ensure_cursor_visible(Window *win) { - int visible_lines = (win->h - 40) / 10 + 3; - if (visible_lines < 1) visible_lines = 1; - - int cursor_line = 0; - for (int i = 0; i < win->cursor_pos && i < win->buf_len; i++) { - if (win->buffer[i] == '\n') cursor_line++; - } - - if (cursor_line < notepad_scroll_line) { - notepad_scroll_line = cursor_line; - } - - if (cursor_line >= notepad_scroll_line + visible_lines) { - notepad_scroll_line = cursor_line - visible_lines + 1; - } -} - -static void notepad_paint(Window *win) { - // Dark mode background for text - draw_rect(win->x + 4, win->y + 30, win->w - 8, win->h - 34, COLOR_NOTEPAD_BG); - - int visual_line = 0; - int current_x = win->x + 8; - int current_y = win->y + 36; - int window_right = win->x + win->w - 16; - - for (int i = 0; i < win->buf_len; i++) { - if (visual_line < notepad_scroll_line) { - if (win->buffer[i] == '\n') { - visual_line++; - current_x = win->x + 8; - current_y = win->y + 36; - } else { - if (current_x >= window_right) { - visual_line++; - current_x = win->x + 8; - current_y += 10; - } - current_x += 8; - } - continue; - } - - if (visual_line >= notepad_scroll_line + (win->h - 40) / 10) { - break; - } - - if (win->buffer[i] == '\n') { - current_x = win->x + 8; - current_y += 10; - visual_line++; - } else { - if (current_x >= window_right) { - current_x = win->x + 8; - current_y += 10; - visual_line++; - - if (visual_line >= notepad_scroll_line + (win->h - 40) / 10) { - break; - } - } - - char ch[2] = {win->buffer[i], 0}; - draw_string(current_x, current_y, ch, COLOR_BLACK); - current_x += 8; - } - } - - // Cursor - if (win->focused) { - int cx = win->x + 8; - int cy = win->y + 36; - int visual_line = 0; - int window_right = win->x + win->w - 16; // Right boundary with padding - - for (int i = 0; i < win->cursor_pos; i++) { - if (win->buffer[i] == '\n') { - cx = win->x + 8; - cy += 10; - visual_line++; - } else { - if (cx >= window_right) { - cx = win->x + 8; - cy += 10; - visual_line++; - } - cx += 8; - } - } - - if (visual_line >= notepad_scroll_line && - visual_line < notepad_scroll_line + (win->h - 40) / 10) { - draw_rect(cx, cy, 2, 8, COLOR_BLACK); - } - } -} - -static void notepad_key(Window *target, char c) { - if (c == 17) { // UP - if (target->cursor_pos > 0) { - int curr = target->cursor_pos; - int line_start = curr; - while (line_start > 0 && target->buffer[line_start - 1] != '\n') { - line_start--; - } - int col = curr - line_start; - - if (line_start > 0) { - int prev_line_end = line_start - 1; - int prev_line_start = prev_line_end; - while (prev_line_start > 0 && target->buffer[prev_line_start - 1] != '\n') { - prev_line_start--; - } - int prev_line_len = prev_line_end - prev_line_start; - if (col > prev_line_len) col = prev_line_len; - target->cursor_pos = prev_line_start + col; - } - } - notepad_ensure_cursor_visible(target); - } else if (c == 18) { // DOWN - int len = target->buf_len; - if (target->cursor_pos < len) { - int curr = target->cursor_pos; - int line_start = curr; - while (line_start > 0 && target->buffer[line_start - 1] != '\n') { - line_start--; - } - int col = curr - line_start; - - int next_line_start = curr; - while (next_line_start < len && target->buffer[next_line_start] != '\n') { - next_line_start++; - } - - if (next_line_start < len) { - next_line_start++; // Skip newline - int next_line_end = next_line_start; - while (next_line_end < len && target->buffer[next_line_end] != '\n') { - next_line_end++; - } - int next_line_len = next_line_end - next_line_start; - if (col > next_line_len) col = next_line_len; - target->cursor_pos = next_line_start + col; - } else { - target->cursor_pos = len; - } - } - notepad_ensure_cursor_visible(target); - } else if (c == 19) { // LEFT - if (target->cursor_pos > 0) target->cursor_pos--; - notepad_ensure_cursor_visible(target); - } else if (c == 20) { // RIGHT - if (target->cursor_pos < target->buf_len) target->cursor_pos++; - notepad_ensure_cursor_visible(target); - } else if (c == '\b') { // Backspace - if (target->cursor_pos > 0) { - // Shift left - for (int i = target->cursor_pos; i < target->buf_len; i++) { - target->buffer[i - 1] = target->buffer[i]; - } - target->buf_len--; - target->cursor_pos--; - target->buffer[target->buf_len] = 0; - notepad_ensure_cursor_visible(target); - } - } else if (c == '\n') { // Enter - if (target->buf_len < 1023) { - // Shift right - for (int i = target->buf_len; i > target->cursor_pos; i--) { - target->buffer[i] = target->buffer[i - 1]; - } - target->buffer[target->cursor_pos] = c; - target->buf_len++; - target->cursor_pos++; - target->buffer[target->buf_len] = 0; - notepad_ensure_cursor_visible(target); - } - } else { - // Printable char - if (target->buf_len < 1023) { - for (int i = target->buf_len; i > target->cursor_pos; i--) { - target->buffer[i] = target->buffer[i - 1]; - } - target->buffer[target->cursor_pos] = c; - target->buf_len++; - target->cursor_pos++; - target->buffer[target->buf_len] = 0; - notepad_ensure_cursor_visible(target); - } - } -} - -void notepad_init(void) { - win_notepad.title = "Notepad"; - win_notepad.x = 100; - win_notepad.y = 100; - win_notepad.w = 400; - win_notepad.h = 300; - win_notepad.visible = false; - win_notepad.buf_len = 0; - win_notepad.cursor_pos = 0; - win_notepad.focused = false; - win_notepad.z_index = 0; - win_notepad.paint = notepad_paint; - win_notepad.handle_key = notepad_key; - win_notepad.handle_click = NULL; - win_notepad.handle_right_click = NULL; - - notepad_scroll_line = 0; - - for(int i=0; i<1024; i++) win_notepad.buffer[i] = 0; -} - -void notepad_reset(void) { - // Clear notepad buffer and reset cursor on close/reopen - win_notepad.buf_len = 0; - win_notepad.cursor_pos = 0; - win_notepad.focused = false; - notepad_scroll_line = 0; - - for(int i=0; i<1024; i++) win_notepad.buffer[i] = 0; -} \ No newline at end of file diff --git a/src/kernel/notepad.h b/src/kernel/notepad.h deleted file mode 100644 index f530c4d..0000000 --- a/src/kernel/notepad.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef NOTEPAD_H -#define NOTEPAD_H - -#include "wm.h" - -extern Window win_notepad; - -void notepad_init(void); -void notepad_reset(void); - -#endif \ No newline at end of file diff --git a/src/kernel/process.c b/src/kernel/process.c index d15538b..6cdf43e 100644 --- a/src/kernel/process.c +++ b/src/kernel/process.c @@ -28,6 +28,8 @@ void process_init(void) { kernel_proc->pml4_phys = paging_get_pml4_phys(); kernel_proc->kernel_stack = 0; + for (int i = 0; i < MAX_PROCESS_FDS; i++) kernel_proc->fds[i] = NULL; + kernel_proc->next = kernel_proc; // Circular linked list current_process = kernel_proc; } @@ -102,7 +104,7 @@ void process_create(void* entry_point, bool is_user) { current_process->next = new_proc; } -void process_create_elf(const char* filepath) { +void process_create_elf(const char* filepath, const char* args_str) { if (process_count >= MAX_PROCESSES) return; process_t *new_proc = &processes[process_count]; @@ -113,6 +115,11 @@ void process_create_elf(const char* filepath) { new_proc->pml4_phys = paging_create_user_pml4_phys(); if (!new_proc->pml4_phys) return; + for (int i = 0; i < MAX_PROCESS_FDS; i++) new_proc->fds[i] = NULL; + new_proc->gui_event_head = 0; + new_proc->gui_event_tail = 0; + new_proc->ui_window = NULL; + // 2. Load ELF executable uint64_t entry_point = elf_load(filepath, new_proc->pml4_phys); if (entry_point == 0) { @@ -127,22 +134,107 @@ void process_create_elf(const char* filepath) { void* stack = kmalloc_aligned(4096, 4096); void* kernel_stack = kmalloc_aligned(16384, 16384); - // Map User stack to 0x800000 -> Note: ELFs might overwrite this if they load there! - // But our ELF loader defaults 0x400000 for standard code. + // Map User stack to 0x800000 paging_map_page(new_proc->pml4_phys, 0x800000, v2p((uint64_t)stack), PT_PRESENT | PT_RW | PT_USER); - // 4. Build Stack Frame + // Parse arguments and push them to the user stack + // We'll place the strings at the very high end of the user stack + int argc = 1; + char *args_buf = (char *)stack + 4096; + uint64_t user_args_buf = 0x800000 + 4096; + + // Copy filepath as argv[0] + int path_len = 0; + while (filepath[path_len]) path_len++; + args_buf -= (path_len + 1); + user_args_buf -= (path_len + 1); + for (int i = 0; i <= path_len; i++) args_buf[i] = filepath[i]; + + uint64_t argv_ptrs[32]; + argv_ptrs[0] = user_args_buf; + + if (args_str) { + int i = 0; + while (args_str[i] && argc < 31) { + // Skip spaces + while (args_str[i] == ' ') i++; + if (!args_str[i]) break; + + int arg_start = i; + bool in_quotes = false; + + if (args_str[i] == '"') { + in_quotes = true; + i++; + arg_start = i; + while (args_str[i] && args_str[i] != '"') i++; + } else { + while (args_str[i] && args_str[i] != ' ') i++; + } + + int arg_len = i - arg_start; + + args_buf -= (arg_len + 1); + user_args_buf -= (arg_len + 1); + + for (int k = 0; k < arg_len; k++) { + args_buf[k] = args_str[arg_start + k]; + } + args_buf[arg_len] = '\0'; + + argv_ptrs[argc++] = user_args_buf; + + if (in_quotes && args_str[i] == '"') i++; // Skip closing quote + } + } + argv_ptrs[argc] = 0; // Null terminator for argv + + // Align stack to 8 bytes before pushing argv array + uint64_t current_user_sp = user_args_buf; + current_user_sp &= ~7ULL; + args_buf = (char *)((uint64_t)stack + (current_user_sp - 0x800000)); + + // Push argv array + int argv_size = (argc + 1) * sizeof(uint64_t); + args_buf -= argv_size; + current_user_sp -= argv_size; + + uint64_t actual_argv_ptr = current_user_sp; // Store the true pointer to argv array + + uint64_t *user_argv_array = (uint64_t *)args_buf; + for (int i = 0; i <= argc; i++) { + user_argv_array[i] = argv_ptrs[i]; + } + + // Align stack to 16 bytes. crt0.asm does `and rsp, -16`, but it's good practice + current_user_sp &= ~15ULL; + + // 4. Build Stack Frame for context switch via IRETQ uint64_t* stack_ptr = (uint64_t*)((uint64_t)kernel_stack + 16384); *(--stack_ptr) = 0x1B; // SS (User Mode Data) - *(--stack_ptr) = 0x800000 + 4096; // RSP + *(--stack_ptr) = current_user_sp; // RSP (Updated user stack pointer) *(--stack_ptr) = 0x202; // RFLAGS (Interrupts Enabled) *(--stack_ptr) = 0x23; // CS (User Mode Code) - *(--stack_ptr) = entry_point; // RIP + *(--stack_ptr) = entry_point; // RIP *(--stack_ptr) = 0; // int_no *(--stack_ptr) = 0; // err_code // 15 General purpose registers - for (int i = 0; i < 15; i++) *(--stack_ptr) = 0; + *(--stack_ptr) = 0; // RAX + *(--stack_ptr) = 0; // RBX + *(--stack_ptr) = 0; // RCX + *(--stack_ptr) = 0; // RDX + *(--stack_ptr) = 0; // RBP + *(--stack_ptr) = argc; // RDI = argc + *(--stack_ptr) = actual_argv_ptr; // RSI = actual argv array + *(--stack_ptr) = 0; // R8 + *(--stack_ptr) = 0; // R9 + *(--stack_ptr) = 0; // R10 + *(--stack_ptr) = 0; // R11 + *(--stack_ptr) = 0; // R12 + *(--stack_ptr) = 0; // R13 + *(--stack_ptr) = 0; // R14 + *(--stack_ptr) = 0; // R15 new_proc->kernel_stack = (uint64_t)kernel_stack + 16384; new_proc->rsp = (uint64_t)stack_ptr; @@ -193,10 +285,20 @@ uint64_t process_terminate_current(void) { // 1. Cleanup side effects if (current_process->ui_window) { + extern void serial_write(const char *str); + serial_write("PROC: Terminating proc with window\n"); wm_remove_window((Window *)current_process->ui_window); current_process->ui_window = NULL; } + extern void fat32_close(struct FAT32_FileHandle *fh); + for (int i = 0; i < MAX_PROCESS_FDS; i++) { + if (current_process->fds[i]) { + fat32_close(current_process->fds[i]); + current_process->fds[i] = NULL; + } + } + extern void cmd_process_finished(void); cmd_process_finished(); @@ -234,9 +336,23 @@ uint64_t process_terminate_current(void) { void process_push_gui_event(process_t *proc, gui_event_t *ev) { if (!proc) return; + + // Coalesce PAINT events: if a PAINT event is already in the queue, don't add another + if (ev->type == 1) { // GUI_EVENT_PAINT + int curr = proc->gui_event_head; + while (curr != proc->gui_event_tail) { + if (proc->gui_events[curr].type == 1) { + return; // Already has a paint event pending + } + curr = (curr + 1) % MAX_GUI_EVENTS; + } + } + int next_tail = (proc->gui_event_tail + 1) % MAX_GUI_EVENTS; // Drop event if queue is full if (next_tail == proc->gui_event_head) { + extern void serial_write(const char *str); + serial_write("PROC: GUI event queue full, dropping event!\n"); return; } proc->gui_events[proc->gui_event_tail] = *ev; diff --git a/src/kernel/process.h b/src/kernel/process.h index a42bb35..344fa93 100644 --- a/src/kernel/process.h +++ b/src/kernel/process.h @@ -6,6 +6,9 @@ #include "gui_ipc.h" #define MAX_GUI_EVENTS 32 +#define MAX_PROCESS_FDS 16 + +struct FAT32_FileHandle; // Registers saved on the stack by interrupts/exceptions typedef struct { @@ -27,12 +30,14 @@ typedef struct process { int gui_event_tail; void *ui_window; // Pointer to the active Window + void *fds[MAX_PROCESS_FDS]; + struct process *next; } process_t; void process_init(void); void process_create(void* entry_point, bool is_user); -void process_create_elf(const char* filepath); +void process_create_elf(const char* filepath, const char* args_str); process_t* process_get_current(void); uint64_t process_schedule(uint64_t current_rsp); uint64_t process_terminate_current(void); diff --git a/src/kernel/process_asm.asm b/src/kernel/process_asm.asm index f04d0c2..3528778 100644 --- a/src/kernel/process_asm.asm +++ b/src/kernel/process_asm.asm @@ -34,3 +34,28 @@ process_jump_usermode: ; Jump to Ring 3! iretq + +; void context_switch_to(uint64_t rsp) +; Restores context from isr frame and jumps +global context_switch_to +context_switch_to: + mov rsp, rdi + + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax + + add rsp, 16 ; drop int_no and err_code + iretq diff --git a/src/kernel/syscall.c b/src/kernel/syscall.c index 6f7ebe4..d4a401e 100644 --- a/src/kernel/syscall.c +++ b/src/kernel/syscall.c @@ -4,6 +4,8 @@ #include "gui_ipc.h" #include "process.h" #include "wm.h" +#include "fat32.h" +#include "fat32.h" // Read MSR static inline uint64_t rdmsr(uint32_t msr) { @@ -67,6 +69,14 @@ static void user_window_click(Window *win, int x, int y) { process_push_gui_event(proc, &ev); } +static void user_window_key(Window *win, char c) { + process_t *proc = (process_t *)win->data; + if (!proc) return; + gui_event_t ev = { .type = GUI_EVENT_KEY, .arg1 = (int)c }; + process_push_gui_event(proc, &ev); +} + + uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5) { extern void cmd_write(const char *str); extern void serial_write(const char *str); @@ -76,37 +86,60 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u // arg2 is the buffer based on our user_test logic cmd_write((const char*)arg2); serial_write((const char*)arg2); - } else if (syscall_num == 0) { // SYS_EXIT - process_t *proc = process_get_current(); - if (proc && proc->ui_window) { - wm_remove_window((Window *)proc->ui_window); - proc->ui_window = NULL; - } - cmd_process_finished(); - // The actual process termination and scheduling will be handled later - // For now this just releases the CMD prompt lock. - // We will eventually need to mark the process_t as DEAD here. + } else if (syscall_num == 0 || syscall_num == 60) { // SYS_EXIT + serial_write("Kernel: SYS_EXIT called\n"); + uint64_t next_rsp = process_terminate_current(); + extern void context_switch_to(uint64_t rsp); + context_switch_to(next_rsp); + + // This point is never reached + while(1); } else if (syscall_num == 3) { // SYS_GUI int cmd = (int)arg1; process_t *proc = process_get_current(); if (cmd == GUI_CMD_WINDOW_CREATE) { + extern void serial_write(const char *str); + serial_write("Kernel: GUI_CMD_WINDOW_CREATE\n"); + const char *title = (const char *)arg2; - uint64_t *params = (uint64_t *)arg3; - if (!params) return 0; + uint64_t *u_params = (uint64_t *)arg3; + if (!u_params) { + serial_write("Kernel: Error - params is NULL\n"); + return 0; + } + + // Copy params from user space to kernel space for safety + uint64_t params[4]; + for (int i = 0; i < 4; i++) params[i] = u_params[i]; + + serial_write("Kernel: Window params copied.\n"); Window *win = kmalloc(sizeof(Window)); - if (!win) return 0; + if (!win) { + serial_write("Kernel: Error - kmalloc failed for Window\n"); + return 0; + } + serial_write("Kernel: Window allocated.\n"); + // Copy title from user space to kernel space so wm.c can access it safely int title_len = 0; - while (title[title_len] && title_len < 255) title_len++; + if (title) { + while (title[title_len] && title_len < 255) title_len++; + } + char *kernel_title = kmalloc(title_len + 1); if (kernel_title) { for (int i = 0; i < title_len; i++) { kernel_title[i] = title[i]; } kernel_title[title_len] = '\0'; + serial_write("Kernel: Title copied: "); + serial_write(kernel_title); + serial_write("\n"); + } else { + serial_write("Kernel: Warning - kernel_title kmalloc failed\n"); } // Basic initialization @@ -116,6 +149,8 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u win->w = (int)params[2]; win->h = (int)params[3]; + serial_write("Kernel: Init win dims.\n"); + // Sanity checks for dimensions if (win->w <= 0 || win->w > 4096) win->w = 400; if (win->h <= 0 || win->h > 4096) win->h = 400; @@ -127,10 +162,15 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u win->buffer[0] = 0; win->data = proc; + serial_write("Kernel: Dims initialized.\n"); + // Safe allocation size_t pixel_size = (size_t)win->w * win->h * 4; win->pixels = kmalloc(pixel_size); win->comp_pixels = kmalloc(pixel_size); + + serial_write("Kernel: Buffers allocated.\n"); + if (win->pixels) { extern void mem_memset(void *dest, int val, size_t len); mem_memset(win->pixels, 0, pixel_size); @@ -140,10 +180,13 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u mem_memset(win->comp_pixels, 0, pixel_size); } + serial_write("Kernel: Buffers cleared.\n"); + + // Set callbacks win->paint = user_window_paint; win->handle_click = user_window_click; win->handle_close = user_window_close; - win->handle_key = NULL; + win->handle_key = user_window_key; win->handle_right_click = NULL; proc->ui_window = win; @@ -152,9 +195,12 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u return (uint64_t)win; } else if (cmd == GUI_CMD_DRAW_RECT) { Window *win = (Window *)arg2; - uint64_t *p = (uint64_t *)arg3; + uint64_t *u_params = (uint64_t *)arg3; uint32_t color = (uint32_t)arg4; - if (win && p) { + if (win && u_params) { + uint64_t params[4]; + for (int i = 0; i < 4; i++) params[i] = u_params[i]; + extern void draw_rect(int x, int y, int w, int h, uint32_t color); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); @@ -163,8 +209,8 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u if (win->pixels) { // Strict user-to-window relative clamping - int rx = (int)p[0]; int ry = (int)p[1]; - int rw = (int)p[2]; int rh = (int)p[3]; + int rx = (int)params[0]; int ry = (int)params[1]; + int rw = (int)params[2]; int rh = (int)params[3]; if (rx < 0) { rw += rx; rx = 0; } if (ry < 0) { rh += ry; ry = 0; } if (rx + rw > win->w) rw = win->w - rx; @@ -176,16 +222,19 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u graphics_set_render_target(NULL, 0, 0); } } else { - draw_rect(win->x + p[0], win->y + p[1], p[2], p[3], color); + draw_rect(win->x + params[0], win->y + params[1], params[2], params[3], color); } asm volatile("push %0; popfq" : : "r"(rflags)); } } else if (cmd == GUI_CMD_DRAW_ROUNDED_RECT_FILLED) { Window *win = (Window *)arg2; - uint64_t *p = (uint64_t *)arg3; + uint64_t *u_params = (uint64_t *)arg3; uint32_t color = (uint32_t)arg4; - if (win && p) { + if (win && u_params) { + uint64_t params[5]; + for (int i = 0; i < 5; i++) params[i] = u_params[i]; + extern void draw_rounded_rect_filled(int x, int y, int w, int h, int radius, uint32_t color); extern void graphics_set_render_target(uint32_t *buffer, int w, int h); @@ -193,9 +242,9 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u asm volatile("pushfq; pop %0; cli" : "=r"(rflags)); if (win->pixels) { - int rx = (int)p[0]; int ry = (int)p[1]; - int rw = (int)p[2]; int rh = (int)p[3]; - int rr = (int)p[4]; + int rx = (int)params[0]; int ry = (int)params[1]; + int rw = (int)params[2]; int rh = (int)params[3]; + int rr = (int)params[4]; if (rx < 0) { rw += rx; rx = 0; } if (ry < 0) { rh += ry; ry = 0; } if (rx + rw > win->w) rw = win->w - rx; @@ -206,8 +255,6 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u draw_rounded_rect_filled(rx, ry, rw, rh, rr, color); graphics_set_render_target(NULL, 0, 0); } - } else { - draw_rounded_rect_filled(win->x + p[0], win->y + p[1], p[2], p[3], p[4], color); } asm volatile("push %0; popfq" : : "r"(rflags)); @@ -251,14 +298,17 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u } } else if (cmd == GUI_CMD_MARK_DIRTY) { Window *win = (Window *)arg2; - uint64_t *p = (uint64_t *)arg3; - if (win && p) { + uint64_t *u_params = (uint64_t *)arg3; + if (win && u_params) { + uint64_t params[4]; + for (int i = 0; i < 4; i++) params[i] = u_params[i]; + // Dual-buffer commit: copy pixels to comp_pixels if (win->pixels && win->comp_pixels) { extern void mem_memcpy(void *dest, const void *src, size_t len); mem_memcpy(win->comp_pixels, win->pixels, (size_t)win->w * win->h * 4); } - wm_mark_dirty(win->x + p[0], win->y + p[1], p[2], p[3]); + wm_mark_dirty(win->x + (int)params[0], win->y + (int)params[1], (int)params[2], (int)params[3]); } } else if (cmd == GUI_CMD_GET_EVENT) { Window *win = (Window *)arg2; @@ -271,6 +321,83 @@ uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, u } return 0; } + } else if (syscall_num == SYS_FS) { + int cmd = (int)arg1; + process_t *proc = process_get_current(); + + if (cmd == FS_CMD_OPEN) { + const char *path = (const char *)arg2; + const char *mode = (const char *)arg3; + if (!path || !mode) return -1; + + FAT32_FileHandle *fh = fat32_open(path, mode); + if (!fh) return -1; + + for (int i = 0; i < MAX_PROCESS_FDS; i++) { + if (proc->fds[i] == NULL) { + proc->fds[i] = fh; + return (uint64_t)i; + } + } + fat32_close(fh); + return -1; + } else if (cmd == FS_CMD_READ) { + int fd = (int)arg2; + void *buf = (void *)arg3; + uint32_t len = (uint32_t)arg4; + if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; + return (uint64_t)fat32_read((FAT32_FileHandle*)proc->fds[fd], buf, (int)len); + } else if (cmd == FS_CMD_WRITE) { + int fd = (int)arg2; + const void *buf = (const void *)arg3; + uint32_t len = (uint32_t)arg4; + if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; + return (uint64_t)fat32_write((FAT32_FileHandle*)proc->fds[fd], buf, (int)len); + } else if (cmd == FS_CMD_CLOSE) { + int fd = (int)arg2; + if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; + fat32_close((FAT32_FileHandle*)proc->fds[fd]); + proc->fds[fd] = NULL; + return 0; + } else if (cmd == FS_CMD_SEEK) { + int fd = (int)arg2; + int offset = (int)arg3; + int whence = (int)arg4; // 0=SET, 1=CUR, 2=END + if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; + return (uint64_t)fat32_seek((FAT32_FileHandle*)proc->fds[fd], offset, whence); + } else if (cmd == FS_CMD_TELL) { + int fd = (int)arg2; + if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; + return (uint64_t)((FAT32_FileHandle*)proc->fds[fd])->position; + } else if (cmd == FS_CMD_SIZE) { + int fd = (int)arg2; + if (fd < 0 || fd >= MAX_PROCESS_FDS || !proc->fds[fd]) return -1; + return (uint64_t)((FAT32_FileHandle*)proc->fds[fd])->size; + } + else if (cmd == FS_CMD_LIST) { + const char *path = (const char *)arg2; + FAT32_FileInfo *entries = (FAT32_FileInfo *)arg3; + int max_entries = (int)arg4; + if (!path || !entries) return -1; + return (uint64_t)fat32_list_directory(path, entries, max_entries); + } else if (cmd == FS_CMD_DELETE) { + const char *path = (const char *)arg2; + if (!path) return -1; + return fat32_delete(path) ? 0 : -1; + } else if (cmd == FS_CMD_MKDIR) { + const char *path = (const char *)arg2; + if (!path) return -1; + return fat32_mkdir(path) ? 0 : -1; + } else if (cmd == FS_CMD_EXISTS) { + const char *path = (const char *)arg2; + if (!path) return 0; + return fat32_exists(path) ? 1 : 0; + } + return 0; + } else if (syscall_num == 8) { // DEBUG_SERIAL_WRITE + extern void serial_write(const char *str); + serial_write((const char *)arg2); + return 0; } return 0; diff --git a/src/kernel/syscall.h b/src/kernel/syscall.h index 8d2ff1c..be4cb56 100644 --- a/src/kernel/syscall.h +++ b/src/kernel/syscall.h @@ -12,8 +12,23 @@ // Syscall Numbers #define SYS_WRITE 1 +#define SYS_GUI 3 +#define SYS_FS 4 #define SYS_EXIT 60 +// FS Commands +#define FS_CMD_OPEN 1 +#define FS_CMD_READ 2 +#define FS_CMD_WRITE 3 +#define FS_CMD_CLOSE 4 +#define FS_CMD_SEEK 5 +#define FS_CMD_TELL 6 +#define FS_CMD_LIST 7 +#define FS_CMD_DELETE 8 +#define FS_CMD_SIZE 9 +#define FS_CMD_MKDIR 10 +#define FS_CMD_EXISTS 11 + void syscall_init(void); uint64_t syscall_handler_c(uint64_t syscall_num, uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4, uint64_t arg5); diff --git a/src/kernel/userland/calculator.c b/src/kernel/userland/calculator.c index bed66c9..f5243c6 100644 --- a/src/kernel/userland/calculator.c +++ b/src/kernel/userland/calculator.c @@ -257,6 +257,9 @@ int main(void) { } else if (ev.type == GUI_EVENT_CLOSE) { sys_exit(0); } + } else { + // Avoid high CPU usage + for(volatile int i=0; i<10000; i++); } } diff --git a/src/kernel/userland/calculator.elf b/src/kernel/userland/calculator.elf index 96cd3a9..a9e333b 100755 Binary files a/src/kernel/userland/calculator.elf and b/src/kernel/userland/calculator.elf differ diff --git a/src/kernel/userland/crash.elf b/src/kernel/userland/crash.elf index c3b4e17..b53e28c 100755 Binary files a/src/kernel/userland/crash.elf and b/src/kernel/userland/crash.elf differ diff --git a/src/kernel/userland/crt0.asm b/src/kernel/userland/crt0.asm index e5adbe2..2eca191 100644 --- a/src/kernel/userland/crt0.asm +++ b/src/kernel/userland/crt0.asm @@ -12,9 +12,6 @@ _start: and rsp, -16 ; Call main(argc, argv) - ; We don't have argc or argv yet, pass 0 - xor rdi, rdi - xor rsi, rsi call main ; If main returns, call exit(status) diff --git a/src/kernel/userland/crt0.o b/src/kernel/userland/crt0.o index e854ec0..3f46cdb 100644 Binary files a/src/kernel/userland/crt0.o and b/src/kernel/userland/crt0.o differ diff --git a/src/kernel/userland/hello.c b/src/kernel/userland/hello.c index bb08af2..fa8e8b5 100644 --- a/src/kernel/userland/hello.c +++ b/src/kernel/userland/hello.c @@ -1,7 +1,42 @@ #include "syscall.h" -int main() { +int strlen(const char* str) { + int len = 0; + while(str[len]) len++; + return len; +} + +void print_int(int n) { + char buf[16]; + if (n == 0) { + sys_write(1, "0", 1); + return; + } + int i = 0; + while(n > 0) { + buf[i++] = (n % 10) + '0'; + n /= 10; + } + for(int j = i - 1; j >= 0; j--) { + sys_write(1, &buf[j], 1); + } +} + +int main(int argc, char** argv) { const char* msg = "Hello from Userland ELF!\n"; sys_write(1, msg, 25); + + sys_write(1, "argc: ", 6); + print_int(argc); + sys_write(1, "\n", 1); + + for (int i = 0; i < argc; i++) { + sys_write(1, "argv[", 5); + print_int(i); + sys_write(1, "]: ", 3); + sys_write(1, argv[i], strlen(argv[i])); + sys_write(1, "\n", 1); + } + return 0; } diff --git a/src/kernel/userland/hello.elf b/src/kernel/userland/hello.elf index b529f97..2a76bbc 100755 Binary files a/src/kernel/userland/hello.elf and b/src/kernel/userland/hello.elf differ diff --git a/src/kernel/userland/hello.o b/src/kernel/userland/hello.o index db3485a..7ff9077 100644 Binary files a/src/kernel/userland/hello.o and b/src/kernel/userland/hello.o differ diff --git a/src/kernel/userland/libc/libui.c b/src/kernel/userland/libc/libui.c index 05b6468..014682b 100644 --- a/src/kernel/userland/libc/libui.c +++ b/src/kernel/userland/libc/libui.c @@ -1,5 +1,6 @@ #include "libui.h" #include "syscall.h" +#include "syscall_user.h" #include extern uint64_t syscall3(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_t arg3); diff --git a/src/kernel/userland/libc/libui.h b/src/kernel/userland/libc/libui.h index 1de681c..9900c56 100644 --- a/src/kernel/userland/libc/libui.h +++ b/src/kernel/userland/libc/libui.h @@ -18,6 +18,7 @@ #define GUI_EVENT_CLICK 2 #define GUI_EVENT_RIGHT_CLICK 3 #define GUI_EVENT_CLOSE 4 +#define GUI_EVENT_KEY 5 typedef struct { int type; @@ -26,7 +27,7 @@ typedef struct { } gui_event_t; // Window Handle -typedef int ui_window_t; +typedef uint64_t ui_window_t; // libui API ui_window_t ui_window_create(const char *title, int x, int y, int w, int h); diff --git a/src/kernel/userland/libc/syscall.c b/src/kernel/userland/libc/syscall.c index e28ad34..b866fdf 100644 --- a/src/kernel/userland/libc/syscall.c +++ b/src/kernel/userland/libc/syscall.c @@ -69,3 +69,48 @@ void sys_exit(int status) { int sys_write(int fd, const char *buf, int len) { return (int)syscall3(SYS_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)len); } + +int sys_open(const char *path, const char *mode) { + return (int)syscall3(SYS_FS, FS_CMD_OPEN, (uint64_t)path, (uint64_t)mode); +} + +int sys_read(int fd, void *buf, uint32_t len) { + return (int)syscall4(SYS_FS, FS_CMD_READ, (uint64_t)fd, (uint64_t)buf, (uint64_t)len); +} + +int sys_write_fs(int fd, const void *buf, uint32_t len) { + return (int)syscall4(SYS_FS, FS_CMD_WRITE, (uint64_t)fd, (uint64_t)buf, (uint64_t)len); +} + +void sys_close(int fd) { + syscall2(SYS_FS, FS_CMD_CLOSE, (uint64_t)fd); +} + +int sys_seek(int fd, int offset, int whence) { + return (int)syscall4(SYS_FS, FS_CMD_SEEK, (uint64_t)fd, (uint64_t)offset, (uint64_t)whence); +} + +uint32_t sys_tell(int fd) { + return (uint32_t)syscall2(SYS_FS, FS_CMD_TELL, (uint64_t)fd); +} + +uint32_t sys_size(int fd) { + return (uint32_t)syscall2(SYS_FS, FS_CMD_SIZE, (uint64_t)fd); +} + +int sys_list(const char *path, struct FAT32_FileInfo *entries, int max_entries) { + return (int)syscall4(SYS_FS, FS_CMD_LIST, (uint64_t)path, (uint64_t)entries, (uint64_t)max_entries); +} + +int sys_delete(const char *path) { + return (int)syscall2(SYS_FS, FS_CMD_DELETE, (uint64_t)path); +} + +int sys_mkdir(const char *path) { + return (int)syscall2(SYS_FS, FS_CMD_MKDIR, (uint64_t)path); +} + +int sys_exists(const char *path) { + return (int)syscall2(SYS_FS, FS_CMD_EXISTS, (uint64_t)path); +} + diff --git a/src/kernel/userland/libc/syscall.h b/src/kernel/userland/libc/syscall.h index e26fcb9..e6227e5 100644 --- a/src/kernel/userland/libc/syscall.h +++ b/src/kernel/userland/libc/syscall.h @@ -6,6 +6,21 @@ // Standard syscalls available from Kernel mode #define SYS_EXIT 0 #define SYS_WRITE 1 +#define SYS_GUI 3 +#define SYS_FS 4 + +// FS Commands +#define FS_CMD_OPEN 1 +#define FS_CMD_READ 2 +#define FS_CMD_WRITE 3 +#define FS_CMD_CLOSE 4 +#define FS_CMD_SEEK 5 +#define FS_CMD_TELL 6 +#define FS_CMD_LIST 7 +#define FS_CMD_DELETE 8 +#define FS_CMD_SIZE 9 +#define FS_CMD_MKDIR 10 +#define FS_CMD_EXISTS 11 // Internal assembly entry into Ring 0 extern uint64_t syscall0(uint64_t sys_num); @@ -19,4 +34,19 @@ extern uint64_t syscall5(uint64_t sys_num, uint64_t arg1, uint64_t arg2, uint64_ void sys_exit(int status); int sys_write(int fd, const char *buf, int len); +// FS API +int sys_open(const char *path, const char *mode); +int sys_read(int fd, void *buf, uint32_t len); +int sys_write_fs(int fd, const void *buf, uint32_t len); +void sys_close(int fd); +int sys_seek(int fd, int offset, int whence); +uint32_t sys_tell(int fd); +uint32_t sys_size(int fd); +int sys_delete(const char *path); +int sys_mkdir(const char *path); +int sys_exists(const char *path); + +struct FAT32_FileInfo; +int sys_list(const char *path, struct FAT32_FileInfo *entries, int max_entries); + #endif diff --git a/src/kernel/userland/libc/syscall.o b/src/kernel/userland/libc/syscall.o index 52f3510..2cbd73f 100644 Binary files a/src/kernel/userland/libc/syscall.o and b/src/kernel/userland/libc/syscall.o differ diff --git a/src/kernel/userland/libc/syscall_user.h b/src/kernel/userland/libc/syscall_user.h new file mode 100644 index 0000000..892e4f2 --- /dev/null +++ b/src/kernel/userland/libc/syscall_user.h @@ -0,0 +1,11 @@ +#ifndef SYSCALL_USER_H +#define SYSCALL_USER_H + +#include "syscall.h" +#include + +static inline void sys_serial_write(const char *str) { + syscall2(8, 0, (uint64_t)str); +} + +#endif diff --git a/src/kernel/userland/notepad.c b/src/kernel/userland/notepad.c new file mode 100644 index 0000000..69d5a18 --- /dev/null +++ b/src/kernel/userland/notepad.c @@ -0,0 +1,251 @@ +#include "libc/syscall.h" +#include "libc/libui.h" +#include "libc/syscall_user.h" +#include + +#define COLOR_NOTEPAD_BG 0xFFFFFFFF +#define COLOR_BLACK 0xFF000000 + +#define NOTEPAD_BUF_SIZE (64 * 1024) +static char buffer[NOTEPAD_BUF_SIZE]; +static int buf_len = 0; +static int cursor_pos = 0; +static int notepad_scroll_line = 0; + +static void notepad_ensure_cursor_visible(int h) { + int visible_lines = (h - 40) / 10 + 3; + if (visible_lines < 1) visible_lines = 1; + + int cursor_line = 0; + for (int i = 0; i < cursor_pos && i < buf_len; i++) { + if (buffer[i] == '\n') cursor_line++; + } + + if (cursor_line < notepad_scroll_line) { + notepad_scroll_line = cursor_line; + } + + if (cursor_line >= notepad_scroll_line + visible_lines) { + notepad_scroll_line = cursor_line - visible_lines + 1; + } +} + +static void notepad_load_state() { + int fd = sys_open("A:/tmp/notepad_state.txt", "r"); + if (fd >= 0) { + sys_serial_write("Notepad: Loading state...\n"); + buf_len = sys_read(fd, buffer, NOTEPAD_BUF_SIZE - 1); + if (buf_len < 0) buf_len = 0; + buffer[buf_len] = 0; + sys_close(fd); + } + cursor_pos = buf_len; +} + +static void notepad_save_state() { + // Ensure dir exists + sys_mkdir("A:/tmp"); + int fd = sys_open("A:/tmp/notepad_state.txt", "w"); + if (fd >= 0) { + sys_write_fs(fd, buffer, buf_len); + sys_close(fd); + } +} + +static void notepad_paint(ui_window_t win, int w, int h) { + ui_draw_rect(win, 4, 30, w - 8, h - 34, COLOR_NOTEPAD_BG); + + int visual_line = 0; + int current_x = 8; + int current_y = 36; + int window_right = w - 16; + + for (int i = 0; i < buf_len; i++) { + if (visual_line < notepad_scroll_line) { + if (buffer[i] == '\n') { + visual_line++; + current_x = 8; + current_y = 36; + } else { + if (current_x >= window_right) { + visual_line++; + current_x = 8; + current_y += 10; + } + current_x += 8; + } + continue; + } + + if (visual_line >= notepad_scroll_line + (h - 40) / 10) { + break; + } + + if (buffer[i] == '\n') { + current_x = 8; + current_y += 10; + visual_line++; + } else { + if (current_x >= window_right) { + current_x = 8; + current_y += 10; + visual_line++; + + if (visual_line >= notepad_scroll_line + (h - 40) / 10) { + break; + } + } + + char ch[2] = {buffer[i], 0}; + ui_draw_string(win, current_x, current_y, ch, COLOR_BLACK); + current_x += 8; + } + } + + // Cursor + int cx = 8; + int cy = 36; + int c_visual_line = 0; + + for (int i = 0; i < cursor_pos; i++) { + if (buffer[i] == '\n') { + cx = 8; + cy += 10; + c_visual_line++; + } else { + if (cx >= window_right) { + cx = 8; + cy += 10; + c_visual_line++; + } + cx += 8; + } + } + + if (c_visual_line >= notepad_scroll_line && + c_visual_line < notepad_scroll_line + (h - 40) / 10) { + ui_draw_rect(win, cx, cy, 2, 8, COLOR_BLACK); + } + + ui_mark_dirty(win, 0, 0, w, h); +} + +static void notepad_key(ui_window_t win, int h, char c) { + if (c == 17) { // UP + if (cursor_pos > 0) { + int curr = cursor_pos; + int line_start = curr; + while (line_start > 0 && buffer[line_start - 1] != '\n') { + line_start--; + } + int col = curr - line_start; + + if (line_start > 0) { + int prev_line_end = line_start - 1; + int prev_line_start = prev_line_end; + while (prev_line_start > 0 && buffer[prev_line_start - 1] != '\n') { + prev_line_start--; + } + int prev_line_len = prev_line_end - prev_line_start; + if (col > prev_line_len) col = prev_line_len; + cursor_pos = prev_line_start + col; + } + } + } else if (c == 18) { // DOWN + if (cursor_pos < buf_len) { + int curr = cursor_pos; + int line_start = curr; + while (line_start > 0 && buffer[line_start - 1] != '\n') { + line_start--; + } + int col = curr - line_start; + + int next_line_start = curr; + while (next_line_start < buf_len && buffer[next_line_start] != '\n') { + next_line_start++; + } + + if (next_line_start < buf_len) { + next_line_start++; // Skip newline + int next_line_end = next_line_start; + while (next_line_end < buf_len && buffer[next_line_end] != '\n') { + next_line_end++; + } + int next_line_len = next_line_end - next_line_start; + if (col > next_line_len) col = next_line_len; + cursor_pos = next_line_start + col; + } else { + cursor_pos = buf_len; + } + } + } else if (c == 19) { // LEFT + if (cursor_pos > 0) cursor_pos--; + } else if (c == 20) { // RIGHT + if (cursor_pos < buf_len) cursor_pos++; + } else if (c == '\b') { // Backspace + if (cursor_pos > 0) { + for (int i = cursor_pos; i < buf_len; i++) { + buffer[i - 1] = buffer[i]; + } + buf_len--; + cursor_pos--; + buffer[buf_len] = 0; + } + } else if (c == '\n') { // Enter + if (buf_len < 1023) { + for (int i = buf_len; i > cursor_pos; i--) { + buffer[i] = buffer[i - 1]; + } + buffer[cursor_pos] = c; + buf_len++; + cursor_pos++; + buffer[buf_len] = 0; + } + } else { + if (buf_len < NOTEPAD_BUF_SIZE - 1) { + for (int i = buf_len; i > cursor_pos; i--) { + buffer[i] = buffer[i - 1]; + } + buffer[cursor_pos] = c; + buf_len++; + cursor_pos++; + buffer[buf_len] = 0; + } + } + notepad_ensure_cursor_visible(h); +} + +int main(int argc, char **argv) { + sys_serial_write("Notepad: Starting userspace main...\n"); + ui_window_t win = ui_window_create("Notepad", 100, 100, 400, 300); + if (win == 0) { + sys_serial_write("Notepad: Failed to create window!\n"); + return 1; + } + sys_serial_write("Notepad: Window created successfully.\n"); + + notepad_load_state(); + + gui_event_t ev; + sys_serial_write("Notepad: Entering event loop...\n"); + while (1) { + if (ui_get_event(win, &ev)) { + if (ev.type == GUI_EVENT_PAINT) { + notepad_paint(win, 400, 300); + } else if (ev.type == GUI_EVENT_KEY) { + notepad_key(win, 300, (char)ev.arg1); + notepad_paint(win, 400, 300); + } else if (ev.type == GUI_EVENT_CLOSE) { + sys_serial_write("Notepad: CLOSE\n"); + notepad_save_state(); + sys_exit(0); + } + } else { + // Optional: sys_yield() or similar to avoid high CPU + // For now, just keep looping but it's better than nothing + for(volatile int i=0; i<10000; i++); + } + } + + return 0; +} diff --git a/src/kernel/userland/notepad.elf b/src/kernel/userland/notepad.elf new file mode 100755 index 0000000..6a39864 Binary files /dev/null and b/src/kernel/userland/notepad.elf differ diff --git a/src/kernel/wm.c b/src/kernel/wm.c index 2900209..a96d049 100644 --- a/src/kernel/wm.c +++ b/src/kernel/wm.c @@ -9,7 +9,7 @@ #include "markdown.h" #include #include -#include "notepad.h" + #include "viewer.h" #include "wallpaper.h" #include "control_panel.h" @@ -21,6 +21,17 @@ #include "paint.h" #include "disk.h" +extern void serial_write(const char *str); + +static bool str_eq(const char *s1, const char *s2) { + if (!s1 || !s2) return false; + while (*s1 && *s2) { + if (*s1 != *s2) return false; + s1++; s2++; + } + return (*s1 == *s2); +} + // --- State --- static int mx = 400, my = 300; // Mouse Pos static int prev_mx = 400, prev_my = 300; // Previous mouse position @@ -120,10 +131,6 @@ static bool str_starts_with(const char *str, const char *prefix) { return true; } -static int str_eq(const char *s1, const char *s2) { - while (*s1 && (*s1 == *s2)) { s1++; s2++; } - return *(const unsigned char*)s1 - *(const unsigned char*)s2; -} static void refresh_desktop_icons(void) { // Update limit in FS @@ -1344,9 +1351,24 @@ void wm_add_window(Window *win) { } } +Window* wm_find_window_by_title(const char *title) { + if (!title) return NULL; + for (int i = 0; i < window_count; i++) { + if (all_windows[i] && all_windows[i]->title && str_eq(all_windows[i]->title, title)) { + return all_windows[i]; + } + } + return NULL; +} + void wm_remove_window(Window *win) { if (!win) return; + serial_write("WM: Removing window '"); + if (win->title) serial_write(win->title); + else serial_write("unknown"); + serial_write("'\n"); + int index = -1; for (int i = 0; i < window_count; i++) { if (all_windows[i] == win) { @@ -1375,6 +1397,8 @@ void wm_remove_window(Window *win) { kfree(win); force_redraw = true; + } else { + serial_write("WM: Window not found in all_windows list!\n"); } } @@ -1824,13 +1848,23 @@ void wm_handle_right_click(int x, int y) { if (str_starts_with(start_menu_pending_app, "Files")) { explorer_open_directory("/"); } else if (str_starts_with(start_menu_pending_app, "Notepad")) { - wm_bring_to_front(&win_notepad); + Window *existing = wm_find_window_by_title("Notepad"); + if (existing) { + wm_bring_to_front(existing); + } else { + process_create_elf("/bin/notepad.elf", NULL); + } } else if (str_starts_with(start_menu_pending_app, "Editor")) { wm_bring_to_front(&win_editor); } else if (str_starts_with(start_menu_pending_app, "Terminal")) { cmd_reset(); wm_bring_to_front(&win_cmd); } else if (str_starts_with(start_menu_pending_app, "Calculator")) { - process_create_elf("/bin/calculator.elf"); + Window *existing = wm_find_window_by_title("Calculator"); + if (existing) { + wm_bring_to_front(existing); + } else { + process_create_elf("/bin/calculator.elf", NULL); + } } else if (str_starts_with(start_menu_pending_app, "Minesweeper")) { wm_bring_to_front(&win_minesweeper); } else if (str_starts_with(start_menu_pending_app, "Settings")) { @@ -1858,9 +1892,9 @@ void wm_handle_right_click(int x, int y) { if (icon->type == 2) { // App Shortcut // Check name to launch app if (str_ends_with(icon->name, "Notepad.shortcut")) { - wm_bring_to_front(&win_notepad); handled = true; + process_create_elf("/bin/notepad.elf", NULL); handled = true; } else if (str_ends_with(icon->name, "Calculator.shortcut")) { - process_create_elf("/bin/calculator.elf"); handled = true; + process_create_elf("/bin/calculator.elf", NULL); handled = true; } else if (str_ends_with(icon->name, "Minesweeper.shortcut")) { wm_bring_to_front(&win_minesweeper); handled = true; } else if (str_ends_with(icon->name, "Settings.shortcut")) { @@ -1912,7 +1946,7 @@ void wm_handle_right_click(int x, int y) { int p=9; int n=0; while(icon->name[n]) path[p++] = icon->name[n++]; path[p]=0; if (str_ends_with(icon->name, ".elf")) { - process_create_elf(path); + process_create_elf(path, NULL); } else if (str_ends_with(icon->name, ".pnt")) { paint_load(path); wm_bring_to_front(&win_paint); @@ -2254,7 +2288,6 @@ void wm_init(void) { disk_manager_scan(); // Drives are now dynamically managed - only real drives are registered - notepad_init(); cmd_init(); explorer_init(); editor_init(); @@ -2269,37 +2302,32 @@ void wm_init(void) { refresh_desktop_icons(); // Initialize z-indices - win_notepad.z_index = 0; - win_cmd.z_index = 1; - win_explorer.z_index = 2; - win_editor.z_index = 3; - win_markdown.z_index = 4; - win_control_panel.z_index = 5; - win_about.z_index = 6; - win_minesweeper.z_index = 7; - win_paint.z_index = 8; + win_cmd.z_index = 0; + win_explorer.z_index = 1; + win_editor.z_index = 2; + win_markdown.z_index = 3; + win_control_panel.z_index = 4; + win_about.z_index = 5; + win_minesweeper.z_index = 6; + win_paint.z_index = 7; + win_viewer.z_index = 8; - all_windows[0] = &win_notepad; - all_windows[1] = &win_cmd; - all_windows[2] = &win_explorer; - all_windows[3] = &win_editor; - all_windows[4] = &win_markdown; - all_windows[5] = &win_control_panel; - all_windows[6] = &win_about; - all_windows[7] = &win_minesweeper; - all_windows[8] = &win_paint; - all_windows[9] = &win_viewer; - window_count = 10; + all_windows[0] = &win_cmd; + all_windows[1] = &win_explorer; + all_windows[2] = &win_editor; + all_windows[3] = &win_markdown; + all_windows[4] = &win_control_panel; + all_windows[5] = &win_about; + all_windows[6] = &win_minesweeper; + all_windows[7] = &win_paint; + all_windows[8] = &win_viewer; + window_count = 9; - // Only show Explorer and Notepad on desktop (Explorer on top) + // Only show Explorer on desktop (initially hidden) win_explorer.visible = false; win_explorer.focused = false; win_explorer.z_index = 10; - win_notepad.visible = false; - win_notepad.focused = false; - win_notepad.z_index = 9; - // Rest are hidden initially win_cmd.visible = false; win_editor.visible = false; diff --git a/src/kernel/wm.h b/src/kernel/wm.h index a349f0c..9fc5631 100644 --- a/src/kernel/wm.h +++ b/src/kernel/wm.h @@ -68,6 +68,7 @@ void wm_process_input(void); void wm_add_window(Window *win); void wm_remove_window(Window *win); void wm_bring_to_front(Window *win); +Window* wm_find_window_by_title(const char *title); // Redraw system void wm_mark_dirty(int x, int y, int w, int h);