From bce944d1498eaa3b6940ee234c863b3548a66b37 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Sun, 24 Jan 2021 12:00:11 -0500 Subject: graphics! --- src/boot.asm | 6 +- src/kernel/elf.c | 10 +- src/kernel/elf.h | 2 +- src/kernel/ide.c | 2 - src/kernel/idt.c | 200 ++++++++++++----- src/kernel/isrs.asm | 44 +++- src/kernel/kbd.c | 410 ++++++++++++++--------------------- src/kernel/kbd.h | 5 +- src/kernel/log.c | 103 +++++++-- src/kernel/log.h | 15 +- src/kernel/main.c | 118 +++------- src/kernel/panic.c | 18 +- src/kernel/pmap.h | 2 +- src/kernel/serial.c | 6 +- src/kernel/task.c | 203 +++++++++++++++-- src/kernel/task.h | 34 ++- src/kernel/util.c | 93 -------- src/kernel/util.h | 8 +- src/kernel/vga.c | 52 ----- src/kernel/vga.h | 12 - src/kernel/window.c | 253 +++++++++++++++++++++ src/kernel/window.h | 23 ++ src/man/dev/kmemmap.pre | 34 --- src/man/index.pre | 13 -- src/shared/include/keypack.h | 137 ++++++++++++ src/shared/include/winact.h | 19 ++ src/user/dirinfo/dirinfo.c | 49 ----- src/user/dumphex/dumphex.c | 81 ------- src/user/dumptext/dumptext.c | 15 -- src/user/fileman/fileman.c | 130 ----------- src/user/hello/hello.asm | 14 -- src/user/highway/cmds.c | 10 +- src/user/highway/line.c | 85 +++++--- src/user/highway/line.h | 1 + src/user/highway/main.c | 31 ++- src/user/highway/vars.c | 28 +-- src/user/include/knob/block.h | 5 + src/user/include/knob/env.h | 9 - src/user/include/knob/format.h | 27 ++- src/user/include/knob/ipc.h | 16 ++ src/user/include/knob/key.h | 8 + src/user/include/knob/panic.h | 9 + src/user/include/knob/task.h | 7 +- src/user/include/knob/user.h | 22 -- src/user/include/libfont/fonts.h | 21 ++ src/user/include/pland/pcrt.h | 7 +- src/user/include/pland/syscall.h | 206 ++++++------------ src/user/include/popups/info.h | 14 ++ src/user/include/popups/popup.h | 23 ++ src/user/include/terminal/readline.h | 10 + src/user/include/terminal/terminal.h | 57 +++++ src/user/init/init.c | 29 ++- src/user/knob/block.c | 24 ++ src/user/knob/env.c | 3 - src/user/knob/file.c | 26 +-- src/user/knob/format.c | 257 ++++++++++++++++++---- src/user/knob/heap.c | 32 +-- src/user/knob/ipc.c | 45 ++++ src/user/knob/key.c | 67 ++++++ src/user/knob/panic.c | 12 + src/user/knob/task.c | 20 +- src/user/knob/user.c | 299 ------------------------- src/user/libfont/bdf.c | 99 +++++++++ src/user/libfont/bdf.h | 8 + src/user/libfont/filist.c | 33 +++ src/user/libfont/filist.h | 8 + src/user/libfont/fonts.c | 66 ++++++ src/user/manual/manual.c | 303 -------------------------- src/user/meminfo/meminfo.c | 41 ++-- src/user/popups/info.c | 99 +++++++++ src/user/popups/popup.c | 45 ++++ src/user/runtimes/c/elf.ld | 1 + src/user/runtimes/c/entry.asm | 42 ---- src/user/runtimes/c/pcrt.asm | 45 ++++ src/user/terminal/readline.c | 104 +++++++++ src/user/terminal/terminal.c | 284 ++++++++++++++++++++++++ 76 files changed, 2701 insertions(+), 1998 deletions(-) delete mode 100644 src/kernel/vga.c delete mode 100644 src/kernel/vga.h create mode 100644 src/kernel/window.c create mode 100644 src/kernel/window.h delete mode 100644 src/man/dev/kmemmap.pre delete mode 100644 src/man/index.pre create mode 100644 src/shared/include/keypack.h create mode 100644 src/shared/include/winact.h delete mode 100644 src/user/dirinfo/dirinfo.c delete mode 100644 src/user/dumphex/dumphex.c delete mode 100644 src/user/dumptext/dumptext.c delete mode 100644 src/user/fileman/fileman.c delete mode 100644 src/user/hello/hello.asm delete mode 100644 src/user/include/knob/env.h create mode 100644 src/user/include/knob/ipc.h create mode 100644 src/user/include/knob/key.h create mode 100644 src/user/include/knob/panic.h delete mode 100644 src/user/include/knob/user.h create mode 100644 src/user/include/libfont/fonts.h create mode 100644 src/user/include/popups/info.h create mode 100644 src/user/include/popups/popup.h create mode 100644 src/user/include/terminal/readline.h create mode 100644 src/user/include/terminal/terminal.h delete mode 100644 src/user/knob/env.c create mode 100644 src/user/knob/ipc.c create mode 100644 src/user/knob/key.c create mode 100644 src/user/knob/panic.c delete mode 100644 src/user/knob/user.c create mode 100644 src/user/libfont/bdf.c create mode 100644 src/user/libfont/bdf.h create mode 100644 src/user/libfont/filist.c create mode 100644 src/user/libfont/filist.h create mode 100644 src/user/libfont/fonts.c delete mode 100644 src/user/manual/manual.c create mode 100644 src/user/popups/info.c create mode 100644 src/user/popups/popup.c delete mode 100644 src/user/runtimes/c/entry.asm create mode 100644 src/user/runtimes/c/pcrt.asm create mode 100644 src/user/terminal/readline.c create mode 100644 src/user/terminal/terminal.c (limited to 'src') diff --git a/src/boot.asm b/src/boot.asm index 28d1a89..08b2834 100644 --- a/src/boot.asm +++ b/src/boot.asm @@ -20,8 +20,7 @@ pae_support equ 0x40 mov ss, ax mov sp, 0x7ffc - mov ah, 0x01 - mov ch, 0x3f + mov ax, 0x0013 int 0x10 mov ax, kernel_segment @@ -90,6 +89,7 @@ bits 32 pmode: mov ax, 0x18 mov ds, ax + mov es, ax mov ss, ax mov esp, 0x00040000 @@ -115,4 +115,4 @@ gdt: dq 0x00cf_f200_0000_ffff;0x28: user data .e: -dw 0xaa55 \ No newline at end of file +dw 0xaa55 diff --git a/src/kernel/elf.c b/src/kernel/elf.c index 60fa3a9..146035e 100644 --- a/src/kernel/elf.c +++ b/src/kernel/elf.c @@ -73,7 +73,7 @@ struct ph_entry { uint32_t align; } __attribute__ ((packed)); -uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma) { +uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma, uint32_t io_handle) { file_id_t h = d->get_file(d, path); if (!h) return 0; @@ -127,8 +127,12 @@ uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_o struct task_state tstate; tstate.page_directory = pd; tstate.ret_addr = ehead.entry_vma; + tstate.stack_bottom = 0; + tstate.edx = (uint32_t)pass_vma; - tstate.wait_mode = NONE; + tstate.esi = active_task - tasks + 1; + tstate.edi = io_handle; + tstate.esp = 0; const char *path_end_start = path; for (const char *i = path; *i; ++i) @@ -144,4 +148,4 @@ uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_o tstate.name[i] = '\0'; return new_task(tstate); -} \ No newline at end of file +} diff --git a/src/kernel/elf.h b/src/kernel/elf.h index 89726c9..1f39afd 100644 --- a/src/kernel/elf.h +++ b/src/kernel/elf.h @@ -4,6 +4,6 @@ #include #include "drive.h" -uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma); +uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_old_vma, uint32_t io_handle); #endif \ No newline at end of file diff --git a/src/kernel/ide.c b/src/kernel/ide.c index 4b6443a..39525ad 100644 --- a/src/kernel/ide.c +++ b/src/kernel/ide.c @@ -93,7 +93,6 @@ static uint32_t ide_ata_rs(const struct drive *d, uint32_t start, uint32_t count static uint32_t ide_ata_ws(const struct drive *d, uint32_t start, uint32_t count, const void *buffer) { PANIC("IDE ATA writing not implemented yet."); - return 0; } static uint32_t ide_atapi_rs(const struct drive *d, uint32_t start, uint32_t count, void *buffer) { @@ -109,7 +108,6 @@ static uint32_t ide_atapi_rs(const struct drive *d, uint32_t start, uint32_t cou static uint32_t ide_atapi_ws(const struct drive *d, uint32_t start, uint32_t count, const void *buffer) { PANIC("IDE ATAPI writing not implemented yet."); - return 0; } static void nop(const struct drive *d) { } diff --git a/src/kernel/idt.c b/src/kernel/idt.c index ebeea17..b8990f2 100644 --- a/src/kernel/idt.c +++ b/src/kernel/idt.c @@ -1,14 +1,14 @@ +#include "paging.h" +#include "window.h" #include "drive.h" -#include "elf.h" -#include "util.h" -#include "idt.h" -#include "log.h" #include "panic.h" -#include "task.h" -#include "paging.h" #include "pmap.h" +#include "task.h" +#include "util.h" +#include "elf.h" +#include "idt.h" #include "kbd.h" -#include "vga.h" +#include "log.h" enum { IDT_PRESENT = 0x80, @@ -35,19 +35,27 @@ struct { //file handles as (drive_number << 8) + file_id_t -static uint32_t sc_open_file(uint32_t drive_number, char *path) { +uint32_t sc_open_file(uint32_t drive_number, char *path) { //not static to ensure sysv abi return (drive_number << 8) + drives[drive_number].get_file(drives + drive_number, path); + //logf(LOG_INFO, "sc_open_file(%d, \"%s\") -> %d", drive_number, path, handle); } -static void sc_close_file(uint32_t handle) { +void sc_close_file(uint32_t handle) { //not static to ensure sysv abi + if (!handle) + return; drives[handle >> 8].free_file(drives + (handle >> 8), handle & 0xff); } -static uint32_t sc_file_get_size(uint32_t handle) { +uint32_t sc_file_get_size(uint32_t handle) { //not static to ensure sysv abi + //logf(LOG_INFO, "sc_file_get_size(%d)", handle); + if (!handle) + return 0; return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff); } -static uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { +uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { //not static to ensure sysv abi + if (!handle) + return 0; uint32_t len = sc_file_get_size(handle); if (file_offset + count > len) count = len - file_offset; @@ -55,14 +63,14 @@ static uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t cou return count; } -static uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass) { +uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t esi_dummy, uint32_t io_task) { //not static to ensure sysv abi switch_to_kernel_cr3(); - uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass); + uint32_t process_id = try_elf_run(drives + drive_number, vma_to_pma(active_task->page_directory, path), pass, io_task); switch_to_task_cr3(); return process_id; } -static void *sc_allocate_ram(uint32_t pages) { +void *sc_allocate_ram(uint32_t pages) { //not static to ensure sysv abi return pd_user_allocate_anywhere_writable(active_task->page_directory, pages); } @@ -75,7 +83,7 @@ enum mi_arg { }; __attribute__ ((pure)) -static uint32_t sc_memory_info(enum mi_arg arg) { +uint32_t sc_memory_info(enum mi_arg arg) { //not static to ensure sysv abi switch (arg) { case MI_KERNEL_MAX: return max_kernel_pages; @@ -92,36 +100,73 @@ static uint32_t sc_memory_info(enum mi_arg arg) { } } -static void sc_wait_for_task(uint32_t handle) { - active_task->wait_mode = PROCESS_END; - active_task->wait_arg = handle; +void sc_wait_for_task(uint32_t handle) { //not static to ensure sysv abi + add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1}); } -static uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct directory_content_info *buffer, uint32_t max_entries) { +uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct directory_content_info *buffer, uint32_t max_entries) { //not static to ensure sysv abi return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries); } -static uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { +uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { //not static to ensure sysv abi return drives[drive_number].n_dir_entries(drives + drive_number, path); } +void sc_get_next_window_action(struct window *w, struct window_action *action) { //not static to ensure sysv abi + *action = next_window_action(w); +} + +void sc_wait_window_action() { + add_wait((struct wait){.mode = WINDOW_ACTION}); +} + +void sc_wait_ipc(uint32_t task_handle) { + add_wait((struct wait){.mode = IPC_RECEIVE, .task = tasks + task_handle - 1}); +} + +void sc_system_log(const char *sz) { + logf(LOG_USER, "[%s] %s", active_task->name, sz); +} + +void sc_wait_any_ipc() { + add_wait((struct wait){.mode = IPC_RECEIVE_ANY}); +} + +void sc_wait_ipc_read(uint32_t handle) { + add_wait((struct wait){.mode = IPC_SEND, .task = tasks + handle - 1}); +} + +__attribute__ ((pure)) +bool sc_is_task_running(uint32_t handle) { + return tasks[handle - 1].page_directory; +} + void const *syscall_table[] = { &sc_open_file, &sc_close_file, &sc_file_read, &sc_file_get_size, &sc_start_task, - &logsz, - &get_key_code, + &ipc_send, + &ipc_read, &sc_allocate_ram, &sc_memory_info, &sc_wait_for_task, &sc_enumerate_dir, - &vga_print_at, + &sc_system_log, &sc_count_of_dir, - &vga_blank, - &vga_set_color, - &vga_swap_color + &new_window, + &del_window, + &resize_window, + &reassign_pixel_buffer, + &push_window_paint, + &sc_get_next_window_action, + &sc_wait_window_action, + &sc_wait_ipc, + &sc_wait_any_ipc, + &find_unread_ipc, + &sc_wait_ipc_read, + &sc_is_task_running }; //these aren't really void ()'s, but gcc complains if we take an address of a void, so we give it a type @@ -141,38 +186,77 @@ extern isr_t ssf_isr; extern isr_t gpf_isr; extern isr_t pff_isr; +enum { + F_ID = 0x00200000, + F_VIP = 0x00100000, + F_VIF = 0x00080000, + F_AC = 0x00040000, + F_VM = 0x00020000, + F_RF = 0x00010000, + F_NT = 0x00004000, + F_OF = 0x00000800, + F_DF = 0x00000400, + F_IF = 0x00000200, + F_TF = 0x00000100, + F_SF = 0x00000080, + F_ZF = 0x00000040, + F_AF = 0x00000010, + F_PF = 0x00000004, + F_CF = 0x00000001, + + F_IOPL_MASK = 0x00003000 +}; + __attribute__ ((noreturn)) -void exception_halt(const char *id, uint32_t code, uint32_t eip, uint32_t cs) { - char nbuf[11]; - - set_log_mode(LOG_PANIC); - logsz("Exception #"); - logsz(id); - logsz(" at 0x"); - u8_hex(cs, nbuf); - logsz(nbuf); - logsz(":0x"); - u32_hex(eip, nbuf); - logsz(nbuf); - - logsz("\nerror code = 0x"); - u32_hex(code, nbuf); - logsz(nbuf); - - logsz("\ntask name = "); - logsz(active_task->name); - - logsz("\ncr3 = 0x"); - uint32_t cr3; - asm ( - "mov %%cr3, %0" - : "=r" (cr3)); - u32_hex(cr3, nbuf); - logsz(nbuf); - - logsz("\nHalting."); - while (1) - asm ("hlt"); +void exception_halt(uint32_t eax, uint32_t ebx, uint32_t ecx, + uint32_t edx, uint32_t esi, uint32_t edi, + const char *id, uint32_t code, + uint32_t eip, uint32_t cs, uint32_t eflags, + uint32_t esp, uint32_t ss) { + if (code) + logf(LOG_ERROR, "Exception #%s (0x%h) in %s", id, code, active_task->name); + else + logf(LOG_ERROR, "Exception #%s in %s:", id, active_task->name); + logf(LOG_ERROR, " cs: 0x%hb ss: 0x%hb", cs, ss); + logf(LOG_ERROR, " eip: 0x%h esp: 0x%h", eip, esp); + logf(LOG_ERROR, " eax: 0x%h ebx: 0x%h", eax, ebx); + logf(LOG_ERROR, " ecx: 0x%h edx: 0x%h", ecx, edx); + logf(LOG_ERROR, " esi: 0x%h edi: 0x%h", esi, edi); + logf(LOG_ERROR, " eflags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + eflags & F_ID ? " ID" : "", eflags & F_VIP ? " VIP" : "", + eflags & F_VIF ? " VIF" : "", eflags & F_AC ? " AC" : "", + eflags & F_VM ? " VM" : "", eflags & F_RF ? " RF" : "", + eflags & F_NT ? " NT" : "", eflags & F_OF ? " OF" : "", + eflags & F_DF ? " DF" : "", eflags & F_IF ? " IF" : "", + eflags & F_TF ? " TF" : "", eflags & F_SF ? " SF" : "", + eflags & F_ZF ? " ZF" : "", eflags & F_AF ? " AF" : "", + eflags & F_PF ? " PF" : "", eflags & F_CF ? " CF" : "", + eflags & ~F_IOPL_MASK ? "" : " none"); + logf(LOG_ERROR, " iopl: %d", (eflags >> 12) & 3); + + logf(LOG_INFO, "Killing %s.", active_task->name); + quit_isr(); + __builtin_unreachable(); +} + +//returns true if stack was expanded +bool pf_check_stack(uint32_t cr2/*, uint32_t edx, uint32_t ecx, uint32_t eax, + uint32_t code, uint32_t eip*/) { +//logf(LOG_INFO, "page fault in %s at 0x%h trying to access 0x%h", active_task->name, eip, cr2); +//logf(LOG_INFO, "stack bottom is 0x%h", active_task->stack_bottom); + + if (cr2 >= active_task->stack_bottom - 0x1000) { + //logf(LOG_INFO, "expanding stack"); + switch_to_kernel_cr3(); + pd_user_allocate(active_task->page_directory, active_task->stack_bottom -= 4096, 1, true); + switch_to_task_cr3(); + //logf(LOG_INFO, "new stack bottom is 0x%h", active_task->stack_bottom); + return true; + } + else { + logf(LOG_ERROR, "Illegal access of 0x%h", cr2); + return false; + } } static void register_int(uint8_t n, isr_t *isr, uint8_t dpl) { @@ -231,4 +315,4 @@ void init_idt() { asm volatile ( "lidt %0" : : "m" (idtr) : "al"); -} \ No newline at end of file +} diff --git a/src/kernel/isrs.asm b/src/kernel/isrs.asm index 472bb40..02b046d 100644 --- a/src/kernel/isrs.asm +++ b/src/kernel/isrs.asm @@ -22,8 +22,9 @@ extern advance_active_task extern on_kbd_isr extern make_sure_tasks extern exception_halt +extern pf_check_stack -n_syscalls equ 0x10 +n_syscalls equ 0x19 ;section .bss ;_debug_is_start_task resb 1 @@ -149,30 +150,59 @@ kbd_isr: udf_isr: push 0 push udid - call exception_halt + jmp exception dfa_isr: push dfid - call exception_halt + jmp exception tsf_isr: push tsid - call exception_halt + jmp exception npf_isr: push npid - call exception_halt + jmp exception ssf_isr: push ssid - call exception_halt + jmp exception gpf_isr: push gpid - call exception_halt + jmp exception pff_isr: + push eax + push ecx + push edx + + mov eax, cr2 + push eax + call pf_check_stack + add esp, 4 + + pop edx + pop ecx + test eax, eax + jz .not_stack + + pop eax + add esp, 4 + iret + +.not_stack: + pop eax push pfid + jmp exception + +exception: + push edi + push esi + push edx + push ecx + push ebx + push eax call exception_halt section .rodata diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c index 8808b74..29c0350 100644 --- a/src/kernel/kbd.c +++ b/src/kernel/kbd.c @@ -1,14 +1,14 @@ #include + +#include "window.h" +#include "drive.h" #include "panic.h" +#include "pmap.h" #include "util.h" +#include "kbd.h" -static uint32_t *kbd_in_pointer; -static uint32_t *kbd_out_pointer; - -#define KBD_BUFFER_LENGTH 1024 -static uint32_t kbd_buffer[KBD_BUFFER_LENGTH]; - -static uint32_t mod_mask; +#define SCANTAB_DIR "sys/scantabs" +#define LAYOUT_HARDCODE_TMP "qwerty" enum { PS2_CMD = 0x64, @@ -30,274 +30,178 @@ enum { PS2G_XT_COMPAT = 0x40 }; -void init_kbd() { - outb(PS2_CMD, PS2C_READ_CONFIG); - uint8_t config = inb(PS2_DATA); - outb(PS2_CMD, PS2C_WRITE_CONFIG); - outb(PS2_DATA, config | PS2G_XT_COMPAT); - - kbd_in_pointer = kbd_buffer; - kbd_out_pointer = kbd_buffer; - mod_mask = 0; -} - -uint32_t get_key_code() { - if (kbd_in_pointer == kbd_out_pointer) - return 0; - uint32_t code = *kbd_out_pointer; - if (++kbd_out_pointer == kbd_buffer + KBD_BUFFER_LENGTH) - kbd_out_pointer = kbd_buffer; - return code; -} +static uint32_t n_scantabs; -enum { - MOD_LSHIFT = 0x00100, - MOD_RSHIFT = 0x00200, - MOD_CAPS = 0x00400, - MOD_INSERT = 0x00800, - MOD_NUMPAD = 0x01000, - MOD_SCROLL = 0x02000, - MOD_LALT = 0x04000, - MOD_RALT = 0x08000, - MOD_LCTRL = 0x10000, - MOD_RCTRL = 0x20000, - MOD_LMETA = 0x40000, - MOD_RMETA = 0x80000 -}; +static struct scantab_info { + uint8_t *scantab; + uint8_t prefix_length; + uint8_t prefix[256]; +} *scantabs; enum { - CODE_CAPS = 0x80, - CODE_INSERT, - CODE_NUMPAD, - CODE_SCROLL, - CODE_LSHIFT, - CODE_RSHIFT, - CODE_LALT, - CODE_RALT, - CODE_LCTRL, - CODE_RCTRL, - CODE_LMETA, - CODE_RMETA, - /* 0x8c - 0x97 reserved */ - /* 0x98 - 0x9f unassigned */ - CODE_F1 = 0xa0, - CODE_F2, - CODE_F3, - CODE_F4, - CODE_F5, - CODE_F6, - CODE_F7, - CODE_F8, - CODE_F9, - CODE_F10, - CODE_F11, - CODE_F12, - /* 0xac - 0xaf unassigned */ - CODE_NUM0 = 0xb0, - CODE_NUM1, - CODE_NUM2, - CODE_NUM3, - CODE_NUM4, - CODE_NUM5, - CODE_NUM6, - CODE_NUM7, - CODE_NUM8, - CODE_NUM9, - CODE_NTIMES, - CODE_NPLUS, - CODE_NENTER, - CODE_NMINUS, - CODE_NDOT, - CODE_NSLASH, - /* 0xc0 unassigned */ - CODE_DELETE = 0xc1, - CODE_HOME, - CODE_END, - CODE_PUP, - CODE_PDOWN, - CODE_UP, - CODE_DOWN, - CODE_LEFT, - CODE_RIGHT, - CODE_ESC, - CODE_MENU, - CODE_PAUSE, - CODE_PRSCR, - /* 0xce - 0xef unassigned */ - CODE_END_LSHIFT = 0xf0, - CODE_END_RSHIFT, - CODE_END_LALT, - CODE_END_RALT, - CODE_END_LCTRL, - CODE_END_RCTRL, - CODE_END_LMETA, - CODE_END_RMETA + ST_ILLEGAL, + ST_SUBTABLE, + ST_FLIP, + ST_SKIP }; -static const uint32_t mod_bits[] = { - MOD_CAPS, - MOD_INSERT, - MOD_NUMPAD, - MOD_SCROLL, - MOD_LSHIFT, - MOD_RSHIFT, - MOD_LALT, - MOD_RALT, - MOD_LCTRL, - MOD_RCTRL, - MOD_LMETA, - MOD_RMETA -}; +void init_kbd() { + outb(PS2_CMD, PS2C_READ_CONFIG); + uint8_t config = inb(PS2_DATA); + outb(PS2_CMD, PS2C_WRITE_CONFIG); + outb(PS2_DATA, config | PS2G_XT_COMPAT); -static const uint32_t *const unmod_bits = mod_bits + 4; + //TODO: get layout from some config file + file_id_t stf = drives->get_file(drives, SCANTAB_DIR "/" LAYOUT_HARDCODE_TMP ".sct"); -//in these tables, 0x00 represents an unknown key, -// and 0xff represents a key release. + fmcpy(&n_scantabs, drives, stf, 0, 4); + scantabs = allocate_kernel_pages((sizeof(struct scantab_info) * n_scantabs - 1) / 4096 + 1); + uint32_t fi = 0x10; + void *st_data = allocate_kernel_pages((n_scantabs - 1) / 8 + 1); -static const uint8_t codes[] = { - 0, CODE_ESC, '1', '2', '3', '4', '5', '6', - '7', '8', '9', '0', '-', '=', '\b', '\t', - 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', - 'o', 'p', '[', ']', '\n', CODE_LCTRL, 'a', 's', - 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', - '\'', '`', CODE_LSHIFT, '\\', 'z', 'x', 'c', 'v', - 'b', 'n', 'm', ',', '.', '/', CODE_RSHIFT, CODE_NTIMES, - CODE_LALT, ' ', CODE_CAPS, CODE_F1, CODE_F2, CODE_F3, CODE_F4, CODE_F5, - CODE_F6, CODE_F7, CODE_F8, CODE_F9, CODE_F10, CODE_NUMPAD, CODE_SCROLL, CODE_NUM7, - CODE_NUM8, CODE_NUM9, CODE_NMINUS, CODE_NUM4, CODE_NUM5, CODE_NUM6, CODE_NPLUS, CODE_NUM1, - CODE_NUM2, CODE_NUM3, CODE_NUM0, CODE_NDOT, 0, 0, 0, CODE_F11, - CODE_F12, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + for (uint32_t n = 0; n < n_scantabs; ++n) { + uint32_t data_sector; + fmcpy(&data_sector, drives, stf, fi, 4); + drives->load_sector(drives, stf, data_sector, st_data + 512 * n); + scantabs[n].scantab = st_data + 512 * n; - 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, CODE_END_LCTRL, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, CODE_END_LSHIFT, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, CODE_END_RSHIFT, 0xff, - CODE_END_LALT, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, - 0xff, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; + uint8_t pl; + fmcpy(&pl, drives, stf, fi + 4, 1); + scantabs[n].prefix_length = pl; + fmcpy(scantabs[n].prefix, drives, stf, fi + 5, pl); -static const uint8_t codes_e0[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, CODE_NENTER, CODE_RCTRL, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, CODE_NSLASH, 0, 0, - CODE_RALT, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, CODE_HOME, - CODE_UP, CODE_PUP, 0, CODE_LEFT, 0, CODE_RIGHT, 0, CODE_END, - CODE_DOWN, CODE_PDOWN, CODE_INSERT, CODE_DELETE, 0, 0, 0, 0, - 0, 0, 0, CODE_LMETA, CODE_RMETA, CODE_MENU, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, + fi += 5 + pl; + if (fi & 0xf) + fi = (fi & ~0xf) + 0x10; + } - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0xff, CODE_END_RCTRL, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0xff, 0, 0, - CODE_END_RALT, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0xff, - 0xff, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, - 0, 0, 0, CODE_END_LMETA, CODE_END_RMETA, 0xff, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 -}; + drives->free_file(drives, stf); +} -#include "log.h" -uint8_t get_code_byte() { +static inline uint8_t get_next_code_byte() { for (uint32_t spin = 0; spin < 10000000; ++spin) ; return inb(PS2_DATA); } +static enum key_modifiers_t keymods = 0; + void on_kbd_isr() { +//logf(LOG_INFO, "on_kbd_isr()"); while (inb(PS2_CMD) & PS2S_CODE_READY) { - //char nbuf[11]; - uint8_t code = get_code_byte(); - //logsz("code: 0x"); - //u8_hex(code, nbuf); - //logsz(nbuf); - if (code == 0xe1) { - code = get_code_byte(); - //logsz(" 0x"); - //u8_hex(code, nbuf); - //logsz(nbuf); - if (code == 0x1d) { - if (get_code_byte() != 0x45) - code = 0; - else - code = CODE_PAUSE; - } - else if (code == 0x9d) { - if (get_code_byte() != 0xc5) - code = 0; - else - code = 0xff; - } - else - code = 0; + uint8_t code[256]; + uint8_t code_i = 0; + sub_table: + code[code_i] = get_next_code_byte(); + const uint8_t *table; + for (uint32_t i = 0; i < n_scantabs; ++i) { + if (scantabs[i].prefix_length != code_i) + continue; + for (uint8_t j = 0; j < code_i; ++j) + if (scantabs[i].prefix[j] != code[j]) + goto next_table; + table = scantabs[i].scantab; + goto got_table; + next_table:; } - else if (code == 0xe0) { - code = get_code_byte(); - //logsz(" 0x"); - //u8_hex(code, nbuf); - //logsz(nbuf); - if (code == 0x2a) { - if ((get_code_byte() != 0xe0) || - (get_code_byte() != 0x37)) - code = 0; - else - code = CODE_PRSCR; - } - else if (code == 0xb7) { - if ((get_code_byte() != 0xe0) || - (get_code_byte() != 0xaa)) - code = 0; - else - code = 0xff; - } - else - code = codes_e0[code]; + PANIC("Couldn't find scantable"); + + got_table:; + bool is_up = false; + flipped_table:; + uint8_t entry = table[code[code_i]]; + switch (entry) { + case ST_ILLEGAL: + PANIC("Illegal scancode encountered"); + case ST_SUBTABLE: + ++code_i; + goto sub_table; + case ST_FLIP: + if (is_up) + PANIC("Recursive flip in scantable"); + table += 0x100; + is_up = true; + goto flipped_table; + case ST_SKIP: + continue; } - else - code = codes[code]; - //logch('\n'); - - if (!code) - PANIC("Unknown scancode."); + switch ((enum key_id_t)entry) { + case KEY_LEFT_SHIFT: + if (is_up) + keymods &= ~LSHIFT; + else + keymods |= LSHIFT; + break; + case KEY_RIGHT_SHIFT: + if (is_up) + keymods &= ~RSHIFT; + else + keymods |= RSHIFT; + break; + case KEY_LEFT_CONTROL: + if (is_up) + keymods &= ~LCTRL; + else + keymods |= LCTRL; + break; + case KEY_RIGHT_CONTROL: + if (is_up) + keymods &= ~RCTRL; + else + keymods |= RCTRL; + break; + case KEY_LEFT_ALT: + if (is_up) + keymods &= ~LALT; + else + keymods |= LALT; + break; + case KEY_RIGHT_ALT: + if (is_up) + keymods &= ~RALT; + else + keymods |= RALT; + break; + case KEY_LEFT_WIN: + if (is_up) + keymods &= ~LWIN; + else + keymods |= LWIN; + break; + case KEY_RIGHT_WIN: + if (is_up) + keymods &= ~RWIN; + else + keymods |= RWIN; + break; + case KEY_CAPS_LOCK: + if (!is_up) + keymods ^= CAPS; + break; + case KEY_NUM_LOCK: + if (!is_up) + keymods ^= NUM; + break; + case KEY_SCROLL_LOCK: + if (!is_up) + keymods ^= SCROLL; + break; + case KEY_INSERT: + if (!is_up) + keymods ^= INSERT; + break; + default: + break; + } - if (code < 0xf0) - *kbd_in_pointer++ = mod_mask | code; - if ((code >= 0x80) && (code <= 0x83)) - mod_mask ^= mod_bits[code & 0x03]; - else if ((code >= 0x84) && (code <= 0x8b)) - mod_mask |= mod_bits[code & 0x0f]; - else if (code >= 0xf0) - mod_mask &= ~unmod_bits[code & 0x0f]; + on_action((struct window_action){ + .action_type = is_up ? KEY_UP : KEY_DOWN, + .as_key = (struct key_packet){ + .key_id = entry, + .modifiers = keymods + } + }); } -} \ No newline at end of file +} diff --git a/src/kernel/kbd.h b/src/kernel/kbd.h index 8a4ed8b..e9affad 100644 --- a/src/kernel/kbd.h +++ b/src/kernel/kbd.h @@ -3,8 +3,9 @@ #include +#include + void init_kbd(); -uint32_t get_key_code(); void on_kbd_isr(); -#endif \ No newline at end of file +#endif diff --git a/src/kernel/log.c b/src/kernel/log.c index b5a96cb..8ef2baf 100644 --- a/src/kernel/log.c +++ b/src/kernel/log.c @@ -1,33 +1,92 @@ -#include "vga.h" +#include +#include + #include "serial.h" #include "log.h" #define LOG_COM COM1 -static const uint8_t log_mode_colors[] = { - 0x30, - 0x07, - 0x4f +void init_log() { + //TODO: move old "sys/current.log" + //TODO: open new "sys/current.log" +} + +static const char *const log_prefixes[] = { + " [USER] ", + " [INFO] ", + " [WARN] ", + "[ERROR] ", + "[PANIC] ", }; -void set_log_mode(enum log_mode mode) { - vga_set_color(log_mode_colors[mode]); - vga_printch('\n'); - vga_printch('\n'); +static inline void logch(char ch) { + sout(LOG_COM, ch); + //TODO: write to log file as well } -void logch(char ch) { - if (ch == '\n') { - sout(LOG_COM, (uint8_t)'\r'); - sout(LOG_COM, (uint8_t)'\n'); - } - else - sout(LOG_COM, (uint8_t)ch); +static const char hex_table[] = "0123456789abcdef"; - vga_printch(ch); -} +void logf(enum log_level level, const char *format, ...) { + va_list args; + va_start(args, format); -void logsz(const char *sz) { - while (*sz) - logch(*sz++); -} \ No newline at end of file + const char *log_prefix = log_prefixes[level]; + while (*log_prefix) + logch(*(log_prefix++)); + + for (const char *fi = format; *fi;) + if (*fi != '%') + logch(*(fi++)); + else { + switch (*(fi + 1)) { + case '%': + logch('%'); + break; + case 's':; + const char *s = va_arg(args, const char *); + while (*s) + logch(*(s++)); + break; + case 'd':; + const uint32_t d = va_arg(args, uint32_t); + if (d == 0) { + logch('0'); + break; + } + bool zeros = false; + for (uint32_t place = 1000000000; place; place /= 10) { + uint8_t digit = (d / place) % 10; + if (digit) + zeros = true; + if (zeros) + logch(digit | '0'); + } + break; + case 'h':; + const uint32_t h = va_arg(args, uint32_t); + uint32_t shift = 32; + if (*(fi + 2) == 'b') { + shift = 8; + ++fi; + } + else if (*(fi + 2) == 'w') { + shift = 16; + ++fi; + } + else if (*(fi + 2) == 'd') { + ++fi; + } + while (shift) + logch(hex_table[(h >> (shift -= 4)) & 0xf]); + break; + default: + logch('%'); + logch(*(fi + 1)); + } + fi += 2; + } + + logch('\n'); + + va_end(args); +} diff --git a/src/kernel/log.h b/src/kernel/log.h index 90a94f4..c5c4da7 100644 --- a/src/kernel/log.h +++ b/src/kernel/log.h @@ -1,16 +1,17 @@ #ifndef LOG_H #define LOG_H -enum log_mode { - LOG_SYSTEM, +#include + +enum log_level { LOG_USER, + LOG_INFO, + LOG_WARN, + LOG_ERROR, LOG_PANIC }; void init_log(); -void set_log_mode(enum log_mode mode); - -void logch(char ch); -void logsz(const char *sz); +void logf(enum log_level level, const char *format, ...); -#endif \ No newline at end of file +#endif diff --git a/src/kernel/main.c b/src/kernel/main.c index b34f816..26cc5e4 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -1,7 +1,8 @@ #include +#include "paging.h" #include "serial.h" +#include "window.h" #include "panic.h" -#include "paging.h" #include "boot.h" #include "util.h" #include "fat.h" @@ -12,57 +13,19 @@ #include "pci.h" #include "elf.h" #include "log.h" -#include "vga.h" #include "kbd.h" void _start_user_mode() __attribute__ ((noreturn)); __attribute__ ((noreturn)) void main() { - char nbuf[11]; - init_pagemap(); init_paging(); init_tasks(); init_serial(); - set_log_mode(LOG_SYSTEM); - vga_blank(); - - logsz("Portland v0.0.11\n\n"); pci_init(); -/* - u16_dec(n_pci_devices, nbuf); - logsz(nbuf); - logsz(" PCI device(s) found:\n"); - - for (uint16_t n = 0; n < n_pci_devices; ++n) { - struct pci_device *pd = nth_pci_device(n); - - u16_hex(pd->number, nbuf); - logsz(" "); - logsz(nbuf); - logsz(": "); - - u16_hex(pd->id_vendor, nbuf); - nbuf[4] = '.'; - u16_hex(pd->id_device, nbuf + 5); - logsz(nbuf); - - u8_hex(pd->class, nbuf); - nbuf[2] = '.'; - u8_hex(pd->subclass, nbuf + 3); - nbuf[5] = '.'; - u8_hex(pd->iface, nbuf + 6); - logsz(" ("); - logsz(nbuf); - logsz(")\n"); - } - - logch('\n'); -*/ - init_fat(); //other fs drivers @@ -71,65 +34,36 @@ void main() { init_ide(); //other drive drivers -/* - u8_dec(n_drives, nbuf); - logsz(nbuf); - logsz(" drive(s) found:\n"); - - for (uint8_t n = 0; n < n_drives; ++n) { - struct drive *d = drives + n; - - u8_dec(n, nbuf); - logsz(" sd"); - logsz(nbuf); - logsz(" ("); - logsz(d->drive_type); - logsz(", "); - - u32_dec(d->n_sectors / 2, nbuf); - logsz(nbuf); - if (d->n_sectors % 2) - logsz(".5"); - logsz("k): "); - - logsz(d->fs_type); - - uint32_t free_sectors = d->get_free_sectors(d); - if (free_sectors != -1) { - u32_dec(free_sectors / 2, nbuf); - logsz(", "); - logsz(nbuf); - if (free_sectors % 2) - logsz(".5"); - logsz("k free"); - } - - logsz(".\n"); - } + init_log(); - logch('\n'); -*/ + init_kbd(); + init_idt(); + + paint_bg(); + + logf(LOG_INFO, "Kernel initialization done."); + logf(LOG_INFO, "Available kernel memory: %dk", kernel_pages_left * 4); + logf(LOG_INFO, "Available user memory: %dk", user_pages_left * 4); + + logf(LOG_INFO, "PCI devices:"); + for (uint16_t i = 0; i < n_pci_devices; ++i) { + const struct pci_device *dev = nth_pci_device(i); + logf(LOG_INFO, " %hw:%hw (%hb:%hb)", dev->id_vendor, dev->id_device, dev->class, dev->subclass); + } - if (BOOT_INFO->support_flags & BIS_PAE) - logsz("Processor supports PAE (but Portland OS does not yet).\n"); - else - logsz("Processor does not support PAE.\n"); + logf(LOG_INFO, "Drives:"); + for (uint8_t i = 0; i < n_drives; ++i) { + const struct drive *d = &drives[i]; + const uint32_t free = d->get_free_sectors(d); + logf(LOG_INFO, " %s: %d%sk, %s (%d%sk free)", d->drive_type, d->n_sectors / 2, d->n_sectors % 2 ? ".5" : "", d->fs_type, free / 2, free % 2 ? ".5" : ""); + } - logsz("Kernel dynamic area size: "); - u32_dec(max_kernel_pages * 4, nbuf); - logsz(nbuf); - logsz("k\nUserspace area size: "); - u32_dec(max_user_pages * 4, nbuf); - logsz(nbuf); - logsz("k\n\n"); + logf(LOG_INFO, "Loading init program."); - if (!try_elf_run(drives, "bin/init", "")) + if (!try_elf_run(drives, "bin/init", "", 0)) PANIC("Failed to load init program."); - init_kbd(); - init_idt(); + logf(LOG_INFO, "Switching to init task."); - logsz("Switching to init task.\n"); - set_log_mode(LOG_USER); _start_user_mode(); } \ No newline at end of file diff --git a/src/kernel/panic.c b/src/kernel/panic.c index 5d32bf7..49fdac1 100644 --- a/src/kernel/panic.c +++ b/src/kernel/panic.c @@ -1,19 +1,11 @@ +#include + #include "log.h" -#include "vga.h" -#include "util.h" __attribute__ ((noreturn)) void panic(const char *filename, uint32_t line, const char *message) { - set_log_mode(LOG_PANIC); - vga_blank(); - logsz("Kernel panic ["); - logsz(filename); - char nbuf[12] = ":"; - u32_dec(line, nbuf + 1); - logsz(nbuf); - logsz("]: "); - logsz(message); - logsz("\nHalting."); + logf(LOG_PANIC, "[%s:%d] %s", filename, line, message); + logf(LOG_INFO, "Halting"); while (1) asm volatile ("hlt"); -} \ No newline at end of file +} diff --git a/src/kernel/pmap.h b/src/kernel/pmap.h index 1016de3..ae58a6c 100644 --- a/src/kernel/pmap.h +++ b/src/kernel/pmap.h @@ -14,4 +14,4 @@ void *allocate_kernel_pages(uint32_t n) __attribute__ ((malloc)); void *allocate_user_pages(uint32_t n) __attribute__ ((malloc)); void free_pages(const void *ptr, uint32_t n); -#endif \ No newline at end of file +#endif diff --git a/src/kernel/serial.c b/src/kernel/serial.c index c492e1e..93bb081 100644 --- a/src/kernel/serial.c +++ b/src/kernel/serial.c @@ -78,8 +78,8 @@ void sout(enum serial_port n, uint8_t b) { serial_spin_t spinner = -1; while (!(inb(ports[n] | CP_LINE_S) & CLS_WRITE)) if (--spinner) { - error[n] = true; - return; + //error[n] = true; + //return; } outb(ports[n] | CP_DATA, b); } @@ -90,4 +90,4 @@ uint8_t sin(enum serial_port n) { while (!(inb(ports[n] | CP_LINE_S) & CLS_READ)) ;//spin return inb(ports[n] | CP_DATA); -} \ No newline at end of file +} diff --git a/src/kernel/task.c b/src/kernel/task.c index 942d1c4..ab08e6b 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -1,6 +1,8 @@ +#include "paging.h" #include "panic.h" +#include "pmap.h" #include "task.h" -#include "paging.h" +#include "util.h" #include "log.h" struct tss { @@ -42,7 +44,7 @@ struct tss { #define MAX_TASKS 64 -static struct task_state tasks[MAX_TASKS]; +struct task_state tasks[MAX_TASKS]; struct task_state *active_task; void init_tasks() { @@ -68,31 +70,68 @@ uint32_t new_task(struct task_state state) { for (uint8_t n = 0; n < MAX_TASKS; ++n) if (!tasks[n].page_directory) { tasks[n] = state; + tasks[n].waiting = false; + for (uint8_t i = 0; i < MAX_WAITS; ++i) + tasks[n].waits[i].mode = NONE; return n + 1; } PANIC("Maximum number of tasks reached."); } +static void tmp_halt() { +//logf(LOG_INFO, "scheduler halting"); + TSS->esp0 = 0x0003c000; + asm("sti\n" + "hlt\n" + "cli"); + TSS->esp0 = 0x00040000; +//logf(LOG_INFO, "scheduler resumed"); +} + void advance_active_task() { - do +//logf(LOG_INFO, "entered scheduler from \"%s\"", active_task->name); + struct task_state *old_task = active_task; + while (1) { if (++active_task == tasks + MAX_TASKS) active_task = tasks; - while (!active_task->page_directory || active_task->wait_mode); + if (active_task->page_directory && !active_task->waiting) { + //logf(LOG_INFO, "exiting scheduler to \"%s\"", active_task->name); + return; + } + if (active_task == old_task) + tmp_halt(); + } } void make_sure_tasks() { for (uint8_t n = 0; n < MAX_TASKS; ++n) if (tasks[n].page_directory) - while (1) { - for (uint8_t n = 0; n < MAX_TASKS; ++n) - if (tasks[n].page_directory && !tasks[n].wait_mode) - return; - asm ("hlt"); - } - set_log_mode(LOG_SYSTEM); - logsz("No tasks, halting."); + return; + logf(LOG_INFO, "No tasks, halting."); while (1) - asm ("hlt"); + asm("hlt"); +} + +//IPC stuff isn't fully implemented, or tested in this version. +//i'm planning to finish and make use of it in the next version, +//making the terminal its own application instead of a library. + +#define MAX_IPC_PIPES 1024 +#define IPC_BUFFER_PAGES 1 + +struct ipc_pipe { + void *buffer; + void *buffer_next_send; + const void *buffer_next_read; + + uint32_t sender_handle; + uint32_t reader_handle; + bool delete_when_empty; +} ipc_pipes[MAX_IPC_PIPES]; + +void delete_pipe(struct ipc_pipe *pipe) { + free_pages(pipe->buffer, IPC_BUFFER_PAGES); + pipe->buffer = 0; } void delete_task(struct task_state *state) { @@ -101,10 +140,136 @@ void delete_task(struct task_state *state) { switch_to_task_cr3(); state->page_directory = 0; - uint32_t handle = state - tasks + 1; - for (uint8_t n = 0; n < MAX_TASKS; ++n) - if (tasks[n].page_directory && - (tasks[n].wait_mode == PROCESS_END) && - (tasks[n].wait_arg == handle)) - tasks[n].wait_mode = NONE; + unwait_any((struct wait){.mode = PROCESS_END, .task = state}); + unwait_any((struct wait){.mode = IPC_RECEIVE, .task = state}); + unwait_any((struct wait){.mode = IPC_SEND, .task = state}); + + const uint32_t handle = active_task - tasks + 1; + for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe) + if (pipe->buffer) { + if (pipe->reader_handle == handle) + delete_pipe(pipe); + else if (pipe->sender_handle == handle) { + if (pipe->buffer_next_read == pipe->buffer_next_send) + delete_pipe(pipe); + else + pipe->delete_when_empty = true; + } + } +} + +uint32_t find_unread_ipc() { + const uint32_t r_handle = active_task - tasks + 1; + for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe) + if (pipe->buffer && (pipe->reader_handle == r_handle) && + (pipe->buffer_next_read != pipe->buffer_next_send)) + return pipe->sender_handle; + return 0; +} + +struct ipc_pipe *get_existing_pipe(uint32_t sender_handle, uint32_t reader_handle) { + for (struct ipc_pipe *i = ipc_pipes; i < ipc_pipes + MAX_IPC_PIPES; ++i) + if (i->buffer && (i->sender_handle == sender_handle) && + (i->reader_handle == reader_handle)) + return i; + return 0; +} + +uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer) { + if (!reader_handle || !tasks[reader_handle - 1].page_directory) + return -1; + + const uint32_t our_handle = active_task - tasks + 1; + struct ipc_pipe *pipe = get_existing_pipe(our_handle, reader_handle); + if (!pipe) { + for (struct ipc_pipe *i = ipc_pipes; i < ipc_pipes + MAX_IPC_PIPES; ++i) + if (!i->buffer) { + i->buffer = allocate_kernel_pages(IPC_BUFFER_PAGES); + i->buffer_next_read = i->buffer; + i->buffer_next_send = i->buffer; + i->reader_handle = reader_handle; + i->sender_handle = our_handle; + i->delete_when_empty = false; + pipe = i; + break; + } + if (!pipe) + PANIC("out of ipc pipes"); + } + + unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_RECEIVE, .task = active_task}); + unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_RECEIVE_ANY}); + + uint32_t send_left = pipe->buffer_next_read - pipe->buffer_next_send - 1; + if (send_left < 0) + send_left += 4096 * IPC_BUFFER_PAGES; + if (count > send_left) + count = send_left; + + if (pipe->buffer_next_send + count < pipe->buffer + 4096 * IPC_BUFFER_PAGES) { + memcpy(pipe->buffer_next_send, buffer, count); + pipe->buffer_next_send += count; + return count; + } + + const uint32_t first_batch = pipe->buffer + 4096 * IPC_BUFFER_PAGES - pipe->buffer_next_send; + memcpy(pipe->buffer_next_send, buffer, first_batch); + memcpy(pipe->buffer, buffer + first_batch, count - first_batch); + pipe->buffer_next_send += count - 4096; + return count; +} + +uint32_t ipc_read(uint32_t sender_handle, uint32_t count, void *buffer) { + if (!sender_handle || !tasks[sender_handle - 1].page_directory) + return -1; + + const uint32_t our_handle = active_task - tasks + 1; + struct ipc_pipe *pipe = get_existing_pipe(sender_handle, our_handle); + if (!pipe) + return 0; + + unwait(tasks + sender_handle - 1, (struct wait){.mode = IPC_SEND, .task = active_task}); + + //TODO +} + +void add_wait(struct wait wait) { + for (uint8_t i = 0; i < MAX_WAITS; ++i) + if (!active_task->waits[i].mode) { + active_task->waits[i] = wait; + active_task->waiting = true; + return; + } + PANIC("Out of waits for task."); +} + +void unwait_any(struct wait wait) { + for (uint8_t i = 0; i < MAX_TASKS; ++i) + if (tasks[i].page_directory) + unwait(tasks + i, wait); +} + +void unwait(struct task_state *task, struct wait wait) { + if (!task->waiting) + return; + for (uint8_t i = 0; i < MAX_WAITS; ++i) { + if (task->waits[i].mode != wait.mode) + continue; + switch (wait.mode) { + case PROCESS_END: + case IPC_RECEIVE: + if (task->waits[i].task != wait.task) + continue; + break; + case WINDOW_ACTION: + case IPC_RECEIVE_ANY: + break; + default: + PANIC("Unwait matched with unrecognized wait mode."); + } + for (uint8_t i = 0; i < MAX_WAITS; ++i) + task->waits[i].mode = NONE; + task->waiting = false; + return; + } } \ No newline at end of file diff --git a/src/kernel/task.h b/src/kernel/task.h index 50be93a..574dfa7 100644 --- a/src/kernel/task.h +++ b/src/kernel/task.h @@ -5,10 +5,20 @@ #include #define TASK_NAME_LEN 15 - -enum wait_mode { - NONE, - PROCESS_END, +#define MAX_WAITS 16 + +struct wait { + enum { + NONE, + PROCESS_END, + WINDOW_ACTION, + IPC_RECEIVE, + IPC_RECEIVE_ANY, + IPC_SEND + } mode; + union { + struct task_state *task; + }; }; struct task_state { @@ -23,12 +33,19 @@ struct task_state { uint32_t ebp; uint32_t esp; - enum wait_mode wait_mode; - uint32_t wait_arg; + uint32_t stack_bottom; + + struct wait waits[MAX_WAITS]; + bool waiting; char name[TASK_NAME_LEN + 1]; } __attribute__ ((packed)); +void add_wait(struct wait wait); +void unwait_any(struct wait wait); +void unwait(struct task_state *task, struct wait wait); + +extern struct task_state tasks[]; extern struct task_state *active_task; void init_tasks(); @@ -38,4 +55,9 @@ void advance_active_task(); void delete_task(struct task_state *state); +uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer); +uint32_t ipc_read(uint32_t sender_handle, uint32_t count, void *buffer); + +uint32_t find_unread_ipc(); + #endif \ No newline at end of file diff --git a/src/kernel/util.c b/src/kernel/util.c index 625622a..ea0496e 100644 --- a/src/kernel/util.c +++ b/src/kernel/util.c @@ -39,97 +39,4 @@ void fmcpy(void *to, const struct drive *d, file_id_t f, uint32_t from, uint32_t d->load_sector(d, f, fsi, buf); memcpy(to + i, buf, n); -} - -void u32_dec(uint32_t n, char *b) { - if (!n) { - *(uint16_t *)b = (uint16_t)'0'; - return; - } - bool zero = false; - for (uint32_t m = 1000000000; m; m /= 10) { - uint8_t d = (n / m) % 10; - if (zero) - *(b++) = d + '0'; - else if (d) { - zero = true; - *(b++) = d + '0'; - } - } - *b = '\0'; -} - -void u16_dec(uint16_t n, char *b) { - if (!n) { - *(uint16_t *)b = (uint16_t)'0'; - return; - } - bool zero = false; - for (uint32_t m = 10000; m; m /= 10) { - uint8_t d = (n / m) % 10; - if (zero) - *(b++) = d + '0'; - else if (d) { - zero = true; - *(b++) = d + '0'; - } - } - *b = '\0'; -} - -void u8_dec(uint8_t n, char *b) { - if (!n) { - *(uint16_t *)b = (uint16_t)'0'; - return; - } - bool zero = false; - for (uint32_t m = 100; m; m /= 10) { - uint8_t d = (n / m) % 10; - if (zero) - *(b++) = d + '0'; - else if (d) { - zero = true; - *(b++) = d + '0'; - } - } - *b = '\0'; -} - -void u32_hex(uint32_t n, char *b) { - uint8_t m = 28; - while (1) { - uint8_t d = (n >> m) & 0xf; - *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d; - if (!m) { - *b = '\0'; - return; - } - m -= 4; - } -} - -void u16_hex(uint16_t n, char *b) { - uint8_t m = 12; - while (1) { - uint8_t d = (n >> m) & 0xf; - *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d; - if (!m) { - *b = '\0'; - return; - } - m -= 4; - } -} - -void u8_hex(uint8_t n, char *b) { - uint8_t m = 4; - while (1) { - uint8_t d = (n >> m) & 0xf; - *(b++) = d >= 10 ? 'a' + d - 10 : '0' + d; - if (!m) { - *b = '\0'; - return; - } - m -= 4; - } } \ No newline at end of file diff --git a/src/kernel/util.h b/src/kernel/util.h index 9fa8002..c5b784a 100644 --- a/src/kernel/util.h +++ b/src/kernel/util.h @@ -44,11 +44,11 @@ static inline uint32_t ind(uint16_t port) { void memcpy(void *to, const void *from, uint32_t n); void fmcpy(void *to, const struct drive *d, file_id_t f, uint32_t from, uint32_t n); -void u32_dec(uint32_t n, char *b); -void u16_dec(uint16_t n, char *b); -void u8_dec(uint8_t n, char *b); +uint8_t u32_dec(uint32_t n, char *b); +uint8_t u16_dec(uint16_t n, char *b); +uint8_t u8_dec(uint8_t n, char *b); void u32_hex(uint32_t n, char *b); void u16_hex(uint16_t n, char *b); void u8_hex(uint8_t n, char *b); -#endif \ No newline at end of file +#endif diff --git a/src/kernel/vga.c b/src/kernel/vga.c deleted file mode 100644 index 6ae1588..0000000 --- a/src/kernel/vga.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -#define VGA_COLUMNS 80 -#define VGA_ROWS 25 -#define VGA_START (uint16_t *)0x000b8000 -#define VGA_END (VGA_START + VGA_COLUMNS * VGA_ROWS) -static uint16_t *cursor = VGA_START; -static uint16_t mask; - -void vga_set_color(uint8_t new_color) { - mask = new_color << 8; -} - -void vga_swap_color(uint16_t pos) { - uint8_t *color_byte = (uint8_t *)(VGA_START + (pos >> 8) * VGA_COLUMNS + (pos & 0xff)) + 1; - *color_byte = (*color_byte << 4) + (*color_byte >> 4); -} - -static void vga_scroll() { - for (uint32_t *i = (uint32_t *)VGA_START; i < (uint32_t *)(VGA_END - VGA_COLUMNS); ++i) - *i = *(i + VGA_COLUMNS / 2); - uint32_t f = (mask | (uint8_t)' ') * 0x00010001; - for (uint32_t *i = (uint32_t *)(VGA_END - VGA_COLUMNS); i < (uint32_t *)VGA_END; ++i) - *i = f; - cursor -= VGA_COLUMNS; -} - -void vga_blank() { - uint32_t f = (mask | (uint8_t)' ') * 0x00010001; - uint32_t *p = (uint32_t *)VGA_START; - while (p < (uint32_t *)VGA_END) - *p++ = f; - cursor = VGA_END - VGA_COLUMNS; -} - -void vga_printch(char ch) { - if (ch == '\n') - cursor = ((cursor - VGA_START) / VGA_COLUMNS + 1) * VGA_COLUMNS + VGA_START; - else if (ch == '\b') - *--cursor = mask | ' '; - else - *cursor++ = mask | (uint8_t)ch; - if (cursor == VGA_END) - vga_scroll(); -} - -void vga_print_at(uint16_t pos, const char *sz) { - cursor = VGA_START + (pos >> 8) * VGA_COLUMNS + (pos & 0xff); - while (*sz) - vga_printch(*sz++); -} \ No newline at end of file diff --git a/src/kernel/vga.h b/src/kernel/vga.h deleted file mode 100644 index dd1c906..0000000 --- a/src/kernel/vga.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef VGA_H -#define VGA_H - -#include - -void vga_print_at(uint16_t pos, const char *sz); -void vga_set_color(uint8_t color); -void vga_blank(); -void vga_printch(char ch); -void vga_swap_color(uint16_t pos); - -#endif \ No newline at end of file diff --git a/src/kernel/window.c b/src/kernel/window.c new file mode 100644 index 0000000..28798d1 --- /dev/null +++ b/src/kernel/window.c @@ -0,0 +1,253 @@ +#include "paging.h" +#include "window.h" +#include "drive.h" +#include "task.h" +#include "util.h" +#include "pmap.h" +#include "log.h" + +#define MAX_WINDOWS 64 +#define ACTION_BUFFER_PAGES 1 +#define AB_END(buf) (buf + (ACTION_BUFFER_PAGES * 4096) / sizeof(struct window_action)) + +#define BACKGROUND(x, y) ((x / 16 + y / 16) % 2 ? 0x14 : 0x07) + +static struct window { + const volatile void *pixel_buffer_pma; + uint16_t width; + uint16_t height; + + uint16_t xpos; + uint16_t ypos; + + struct window_action *action_buffer; + struct window_action *next_action_read; + struct window_action *next_action_write; + + struct window *above; + struct window *below; + + struct task_state *from_task; +} windows[MAX_WINDOWS]; + +static struct window *bottom_window = 0; +static struct window *top_window = 0; + +static inline void set_pix(uint16_t x, uint16_t y, uint8_t value) { + if ((x < 320) && (y < 200)) + *(uint8_t *)(0xa0000 + y * 320 + x) = value; +} + +static void paint_and_above(const struct window *w) { + switch_to_kernel_cr3(); + for (const struct window *i = w; i; i = i->above) + for (uint16_t y = 0; y < i->height; ++y) + for (uint16_t x = 0; x < i->width; ++x) { + const uint8_t pixel = ((uint8_t *)i->pixel_buffer_pma)[y * i->width + x]; + if (pixel) + set_pix(x + i->xpos, y + i->ypos, pixel); + } + switch_to_task_cr3(); +} + +void paint_bg() { + for (uint16_t y = 0; y < 200; ++y) + for (uint16_t x = 0; x < 320; ++x) + set_pix(x, y, BACKGROUND(x, y)); +} + +static void paint_all() { + paint_bg(); + paint_and_above(bottom_window); +} + +struct window *new_window(uint16_t width, uint16_t height, const void *pixel_buffer) { + if (!pixel_buffer) { + logf(LOG_WARN, "Refusing to create window with null pixel buffer for task %s.", active_task->name); + return 0; + } + + struct window *w; + for (uint8_t i = 0; i < MAX_WINDOWS; ++i) + if (!windows[i].pixel_buffer_pma) { + w = &windows[i]; + goto got_window; + } + return 0; +got_window: + + w->pixel_buffer_pma = vma_to_pma(active_task->page_directory, pixel_buffer); + w->width = width; + w->height = height; + + struct window_action *const ab = allocate_kernel_pages(ACTION_BUFFER_PAGES); + w->action_buffer = ab; + w->next_action_read = ab; + w->next_action_write = ab; + + if (top_window) + top_window->above = w; + else + bottom_window = w; + w->above = 0; + w->below = top_window; + top_window = w; + + w->from_task = active_task; + + paint_and_above(w); + return w; +} + +void del_window(struct window *w) { + if (w == top_window) + top_window = w->below; + if (w == bottom_window) + bottom_window = w->above; + if (w->below) + w->below->above = w->above; + if (w->above) + w->above->below = w->below; + + free_pages(w->action_buffer, ACTION_BUFFER_PAGES); + w->pixel_buffer_pma = 0; + + paint_all(); +} + +void resize_window(struct window *w, uint16_t width, uint16_t height) { + const bool smaller = (width < w->width) || (height < w->height); + + w->width = width; + w->height = height; + + if (smaller) + paint_all(); + else + paint_and_above(w); +} + +void reassign_pixel_buffer(struct window *w, const void *pixel_buffer) { + w->pixel_buffer_pma = vma_to_pma(active_task->page_directory, pixel_buffer); +} + +void push_window_paint(const struct window *w) { + paint_and_above(w); +} + +struct window_action next_window_action(struct window *w) { + if (w->next_action_write == w->next_action_read) + return (struct window_action){.action_type = NONE}; + const struct window_action *const action = w->next_action_read; + if (++(w->next_action_read) >= AB_END(w->action_buffer)) + w->next_action_read = w->action_buffer; + return *action; +} + +static void send_action(struct window *w, struct window_action packet) { + struct window_action *next_next = w->next_action_write + 1; + if (next_next >= AB_END(w->action_buffer)) + next_next = w->action_buffer; + if (next_next != w->next_action_read) { + *(w->next_action_write) = packet; + w->next_action_write = next_next; + unwait(w->from_task, (struct wait){.mode = WINDOW_ACTION}); + } +} + +enum wm_action { + WM_SHUFFLE_UP, + WM_SHUFFLE_DOWN, + WM_MOVE_LEFT, + WM_MOVE_RIGHT, + WM_MOVE_UP, + WM_MOVE_DOWN, + + N_WM_ACTIONS +}; + +static struct key_packet keybinds[] = { + {.key_id = KEY_PAGE_DOWN, .modifiers = WINS}, + {.key_id = KEY_PAGE_UP, .modifiers = WINS}, + {.key_id = KEY_LEFT_ARROW, .modifiers = WINS}, + {.key_id = KEY_RIGHT_ARROW, .modifiers = WINS}, + {.key_id = KEY_UP_ARROW, .modifiers = WINS}, + {.key_id = KEY_DOWN_ARROW, .modifiers = WINS} +}; + +static inline bool fuzzy_key_match(struct key_packet t, struct key_packet a) { + if (t.key_id != a.key_id) + return false; + + if (((t.modifiers & SHIFTS) == SHIFTS) && (a.modifiers & SHIFTS)) + a.modifiers |= SHIFTS; + if (((t.modifiers & CTRLS) == CTRLS) && (a.modifiers & CTRLS)) + a.modifiers |= CTRLS; + if (((t.modifiers & ALTS) == ALTS) && (a.modifiers & ALTS)) + a.modifiers |= ALTS; + if (((t.modifiers & WINS) == WINS) && (a.modifiers & WINS)) + a.modifiers |= WINS; + + return a.modifiers == t.modifiers; +} + +#include "log.h" + +void on_action(struct window_action packet) { +//logf(LOG_INFO, "Window action, top window = 0x%d from %s.", top_window, top_window->from_task->name); + + if (packet.action_type == NOT_READY) + return; + + if (top_window) { + if (packet.action_type == KEY_DOWN) + for (uint8_t i = 0; i < N_WM_ACTIONS; ++i) + if (fuzzy_key_match(keybinds[i], packet.as_key)) { + switch_to_kernel_cr3(); + struct window *old_top, *old_bottom; + switch (i) { + case WM_SHUFFLE_UP: + old_top = top_window; + old_bottom = bottom_window; + top_window = old_top->below; + top_window->above = 0; + old_top->below = 0; + old_top->above = old_bottom; + old_bottom->below = old_top; + bottom_window = old_top; + paint_and_above(bottom_window->above); + break; + case WM_SHUFFLE_DOWN: + old_top = top_window; + old_bottom = bottom_window; + bottom_window = old_bottom->above; + bottom_window->below = 0; + old_bottom->above = 0; + old_bottom->below = old_top; + old_top->above = old_bottom; + top_window = old_bottom; + paint_and_above(top_window); + break; + case WM_MOVE_LEFT: + --top_window->xpos; + paint_all(); + break; + case WM_MOVE_RIGHT: + ++top_window->xpos; + paint_all(); + break; + case WM_MOVE_UP: + --top_window->ypos; + paint_all(); + break; + case WM_MOVE_DOWN: + ++top_window->ypos; + paint_all(); + } + switch_to_task_cr3(); + return; + } + + send_action(top_window, packet); + } +} \ No newline at end of file diff --git a/src/kernel/window.h b/src/kernel/window.h new file mode 100644 index 0000000..60b81ea --- /dev/null +++ b/src/kernel/window.h @@ -0,0 +1,23 @@ +#ifndef WINDOW_H +#define WINDOW_H + +#include + +#include + +struct window; + +void paint_bg(); + +struct window *new_window(uint16_t width, uint16_t height, const void *pixel_buffer); +void del_window(struct window *w); + +void resize_window(struct window *w, uint16_t width, uint16_t height); +void reassign_pixel_buffer(struct window *w, const void *pixel_buffer); +void push_window_paint(const struct window *w); +struct window_action next_window_action(struct window *w); +void wait_window_action(); + +void on_action(struct window_action packet); + +#endif diff --git a/src/man/dev/kmemmap.pre b/src/man/dev/kmemmap.pre deleted file mode 100644 index 73b4e09..0000000 --- a/src/man/dev/kmemmap.pre +++ /dev/null @@ -1,34 +0,0 @@ -\title{Portland Kernel Memory Map} - -This manual page describes the layout of the kernel area of memory. Unless you are doing kernel development, you do not need to know this. This is not guaranteed to remain backwards-compatible across versions. Unspecified memory under \color{07}0x0400.0000\color{0f} is reserved for future use. - -\color{0e}Passed from bootloader\color{0f} - -Starting at \color{07}0x0000.4000\color{0f} is information passed from the bootloader. - -\color{07}0x4000 byte:\color{0f} support flags -- \color{07}0x80:\color{0f} PCI support -- \color{07}0x40:\color{0f} PAE support -- The other flags are reserved. -\color{07}0x4001 byte:\color{0f} PCI's "hardware characteristics" byte -\color{07}0x4002 byte:\color{0f} PCI's minor version -\color{07}0x4003 byte:\color{0f} PCI's major version -\color{07}0x4004 byte:\color{0f} last PCI bus -\color{07}0x4006 word:\color{0f} length of BIOS's memory map - -From \color{07}0x0001.0000\color{0f} to \color{07}0x0001.ffff\color{0f} is the memory map from BIOS. - -\color{0e}Fixed kernel structures\color{0f} - -\color{07}0x0000.4f98 - 0x0000.4fff:\color{0f} the Task State Segment -\color{07}0x0000.5000 - 0x0000.5fff:\color{0f} identity page directory -\color{07}0x0004.0000 - 0x0005.ffff:\color{0f} a bitmap of allocated pages -\color{07}0x0040.0000 - 0x007f.ffff:\color{0f} page tables referenced by identity page directory - -\color{0e}Others\color{0f} - -\color{07}0x000a.0000 - 0x000f.0000\color{0f} and \color{07}0x00f0.0000 - 0x00ff.0000\color{0f} are assumed to be reserved by the motherboard for either memory-mapped hardware or BIOS. The standard VGA area is used as such, and the rest are avoided. - -The kernel is loaded with the text and data sections at \color{07}0x0003.0000 - 0x0003.7fff\color{0f}, and the bss at \color{07}0x0400.0000 - 0x07ff.7fff\color{0f}. \color{07}0x0003.8000 - 0x0003.ffff\color{0f} is used as a stack by the kernel, and whatever part of the bss area is unused is used as a sort of page-resolution "heap" for the kernel. - -Everything after \color{07}0x0800.0000\color{0f} that the BIOS indicates is available for use is used for user pages. \ No newline at end of file diff --git a/src/man/index.pre b/src/man/index.pre deleted file mode 100644 index 49f3d13..0000000 --- a/src/man/index.pre +++ /dev/null @@ -1,13 +0,0 @@ -\title{Portland Manual Index} - -Use the \color{07}up\color{0f} and \color{07}down\color{0f} arrows to scroll the manual one line at a time, or the \color{07}page up\color{0f} and \color{07}page down\color{0f} buttons to scroll a whole page at a time. Use the \color{07}left\color{0f} and \color{07}right\color{0f} arrows to focus the previous or next link, and the \color{07}space\color{0f} or \color{07}enter\color{0f} keys to follow those links. Use \color{07}escape\color{0f} to go back to the previous page, and \color{07}q\color{0f} to quit. - -\color{0e}Programs\color{0f} -\link{fileman (file manager):bin/fileman} -\link{Highway (command shell):bin/highway} - -\color{0e}Development\color{0f} -\link{System calls:dev/syscalls} -\link{Keycodes:dev/keycodes} -\link{Manual file format:dev/manfile} -\link{Kernel memory map:dev/kmemmap} \ No newline at end of file diff --git a/src/shared/include/keypack.h b/src/shared/include/keypack.h new file mode 100644 index 0000000..1b356a3 --- /dev/null +++ b/src/shared/include/keypack.h @@ -0,0 +1,137 @@ +#ifndef SHARED_KEYPACK_H +#define SHARED_KEYPACK_H + +struct key_packet { + enum key_id_t { + KEY_BSPACE = 0x08, + KEY_TAB, + KEY_ENTER, + KEY_SPACE = ' ', + KEY_APOSTRAPHE = '\'', + KEY_COMMA = ',', + KEY_HYPHEN, + KEY_PERIOD, + KEY_SLASH, + KEY_ZERO, + KEY_ONE, + KEY_TWO, + KEY_THREE, + KEY_FOUR, + KEY_FIVE, + KEY_SIX, + KEY_SEVEN, + KEY_EIGHT, + KEY_NINE, + KEY_SEMICOLON = ';', + KEY_EQUALS = '=', + KEY_OPEN_BRACKET = '[', + KEY_BACKSLASH, + KEY_CLOSE_BRACKET, + KEY_GRAVE = '`', + KEY_A, + KEY_B, + KEY_C, + KEY_D, + KEY_E, + KEY_F, + KEY_G, + KEY_H, + KEY_I, + KEY_J, + KEY_K, + KEY_L, + KEY_M, + KEY_N, + KEY_O, + KEY_P, + KEY_Q, + KEY_R, + KEY_S, + KEY_T, + KEY_U, + KEY_V, + KEY_W, + KEY_X, + KEY_Y, + KEY_Z, + + KEY_LEFT_SHIFT = 0x80, + KEY_RIGHT_SHIFT, + KEY_LEFT_CONTROL, + KEY_RIGHT_CONTROL, + KEY_LEFT_ALT, + KEY_RIGHT_ALT, + KEY_LEFT_WIN, + KEY_RIGHT_WIN, + KEY_CAPS_LOCK, + KEY_NUM_LOCK, + KEY_SCROLL_LOCK, + KEY_INSERT, + + KEY_F1 = 0xa0, + KEY_F2, + KEY_F3, + KEY_F4, + KEY_F5, + KEY_F6, + KEY_F7, + KEY_F8, + KEY_F9, + KEY_F10, + KEY_F11, + KEY_F12, + KEY_NUM_ZERO = 0xb0, + KEY_NUM_ONE, + KEY_NUM_TWO, + KEY_NUM_THREE, + KEY_NUM_FOUR, + KEY_NUM_FIVE, + KEY_NUM_SIX, + KEY_NUM_SEVEN, + KEY_NUM_EIGHT, + KEY_NUM_NINE, + KEY_NUM_TIMES, + KEY_NUM_PLUS, + KEY_NUM_ENTER, + KEY_NUM_MINUS, + KEY_NUM_DOT, + KEY_NUM_DIVIDE, + KEY_DELETE = 0xc1, + KEY_HOME, + KEY_END, + KEY_PAGE_UP, + KEY_PAGE_DOWN, + KEY_UP_ARROW, + KEY_DOWN_ARROW, + KEY_LEFT_ARROW, + KEY_RIGHT_ARROW, + KEY_ESCAPE, + KEY_MENU, + KEY_PAUSE, + KEY_PRINT_SCREEN + } key_id; + enum key_modifiers_t { + LSHIFT = 0x001, + RSHIFT = 0x002, + LCTRL = 0x004, + RCTRL = 0x008, + LALT = 0x010, + RALT = 0x020, + LWIN = 0x040, + RWIN = 0x080, + + CAPS = 0x100, + NUM = 0x200, + SCROLL = 0x400, + INSERT = 0x800, + + SHIFTS = 0x003, + CTRLS = 0x00c, + ALTS = 0x030, + WINS = 0x0c0, + + NO_MODS = 0x000 + } modifiers; +} __attribute__ ((__packed__)); + +#endif \ No newline at end of file diff --git a/src/shared/include/winact.h b/src/shared/include/winact.h new file mode 100644 index 0000000..bc18cb4 --- /dev/null +++ b/src/shared/include/winact.h @@ -0,0 +1,19 @@ +#ifndef SHARED_WINACT_H +#define SHARED_WINACT_H + +#include + +struct window_action { + enum { + NOT_READY, + KEY_DOWN, + KEY_UP, + FOCUS_ENTER, + FOCUS_LEAVE + } action_type; + union { + struct key_packet as_key; + }; +} __attribute__ ((__packed__)); + +#endif \ No newline at end of file diff --git a/src/user/dirinfo/dirinfo.c b/src/user/dirinfo/dirinfo.c deleted file mode 100644 index 21afcc7..0000000 --- a/src/user/dirinfo/dirinfo.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include - -#define MAX_DIR_ENTRIES 20 - -void main(const char *arg) { - uint8_t dn; - const char *path = remove_prefix(arg, &dn); - - tell_user_sz("Directory info for "); - tell_user_sz(*arg ? arg : "drive root"); - tell_user_sz("\n"); - - _dir_info_entry_t infos[MAX_DIR_ENTRIES]; - uint8_t count = _enumerate_dir(dn, path, infos, MAX_DIR_ENTRIES); - tell_user_sz( - count == MAX_DIR_ENTRIES - ? "Truncated to 20 entries.\n\n" - : "\n" - ); - - uint32_t total_size = 0; - - if (!count) - tell_user_sz("(none)\n"); - - for (uint8_t i = 0; i < count; ++i) { - tell_user_sz(infos[i].name); - tell_user_sz(": "); - if (infos[i].is_dir) - tell_user_sz("dir"); - else { - char nbuf[11]; - itosz(infos[i].size, nbuf); - tell_user_sz(nbuf); - tell_user_sz(" bytes"); - total_size += infos[i].size; - } - tell_user_sz("\n"); - } - - tell_user_sz("\nTotal size without subdirectories: "); - char nbuf[11]; - itosz(total_size, nbuf); - tell_user_sz(nbuf); - tell_user_sz(" bytes\n"); -} \ No newline at end of file diff --git a/src/user/dumphex/dumphex.c b/src/user/dumphex/dumphex.c deleted file mode 100644 index 2944a2f..0000000 --- a/src/user/dumphex/dumphex.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include -#include - -#define LINE_LEN 16 - -void print_zero_line(uint32_t offset) { -} - -void main(const char *path) { - struct file *f = open_file(path); - if (!f) { - tell_user_sz("Couldn't open file.\n"); - return; - } - - uint8_t line[LINE_LEN + 2]; - uint8_t len; - uint32_t offset = -LINE_LEN; - - enum { - ZR_NO, - ZR_FIRST, - ZR_REST - } zero_run; - - char nbuf[9]; - - while ((len = read_from_file(f, LINE_LEN, line))) { - offset += LINE_LEN; - - for (uint8_t i = 0; i < LINE_LEN; ++i) - if (line[i]) { - zero_run = ZR_NO; - goto print_normal; - } - - switch (zero_run) { - case ZR_NO: - zero_run = ZR_FIRST; - _log_string("0x"); - itosz_h32(offset, nbuf); - _log_string(nbuf); - _log_string(" | 00 00 00 00 00 00 00 00 " - "00 00 00 00 00 00 00 00 |\n"); - continue; - case ZR_FIRST: - zero_run = ZR_REST; - tell_user_sz("...\n"); - case ZR_REST: - continue; - } - - print_normal: - _log_string("0x"); - itosz_h32(offset, nbuf); - _log_string(nbuf); - _log_string(" |"); - - nbuf[0] = ' '; - for (uint8_t i = 0; i < len; ++i) { - itosz_h8(line[i], nbuf + 1); - _log_string(nbuf); - } - - for (uint8_t i = len; i < LINE_LEN; ++i) - _log_string(" "); - - _log_string(" | "); - - for (uint8_t i = 0; i < len; ++i) - if ((line[i] < 0x20) || (line[i] > 0x7e)) - line[i] = ' '; - line[len] = '\n'; - line[len + 1] = '\0'; - - _log_string(line); - } - - close_file(f); -} \ No newline at end of file diff --git a/src/user/dumptext/dumptext.c b/src/user/dumptext/dumptext.c deleted file mode 100644 index b10375c..0000000 --- a/src/user/dumptext/dumptext.c +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -void main(const char *path) { - struct file *f = open_file(path); - if (!f) { - tell_user_sz("Couldn't open file.\n"); - return; - } - char buf[] = { '\0', '\0' }; - while (read_from_file(f, 1, buf)) - tell_user_sz(buf); - tell_user_sz("\n"); - close_file(f); -} \ No newline at end of file diff --git a/src/user/fileman/fileman.c b/src/user/fileman/fileman.c deleted file mode 100644 index 0b28d1d..0000000 --- a/src/user/fileman/fileman.c +++ /dev/null @@ -1,130 +0,0 @@ -#include -#include -#include -#include -#include - -char path_sz[1024] = ""; -uint32_t path_len = 0; - -_dir_info_entry_t *dir_info; -uint32_t dir_info_len; - -uint32_t scroll; -uint32_t selected; -#define MAX_PER_SCREEN 18 - -void paint_screen() { - _clear_screen(); - - _set_color(0x70); - _print_at(0, 0, path_sz); - _log_string("/"); - _set_color(0x07); - - for (uint32_t i = scroll, row = 2; (i < dir_info_len) && (row < MAX_PER_SCREEN + 2); ++i, ++row) { - if (i == selected) - _set_color(0x17); - _print_at(row, 0, dir_info[i].name); - if (dir_info[i].is_dir) - _log_string("/"); - if (i == selected) - _set_color(0x07); - } - - _print_at(21, 0, "keybindings:\n" - "UP, DOWN, PAGE UP, PAGE DOWN, HOME, END: move selection\n" - "ENTER: enter selected directory, run selected program\n" - "ESC: go up a directory Q: quit"); -} - -void load_dir() { - free_block(dir_info); - dir_info = get_directory_info(path_sz, &dir_info_len); - scroll = 0; - selected = 0; -} - -void main(const char *sz) { - path_len = strcpy(path_sz, sz); - dir_info = get_directory_info(sz, &dir_info_len); - - paint_screen(); - - while (true) { - _key_code_t key; - switch (key = _get_key()) { - case 0: - _yield_task(); - continue; - case '\n': - { - uint32_t old_len = path_len; - if (path_len) - path_sz[path_len++] = '/'; - path_len += strcpy(path_sz + path_len, dir_info[selected].name); - if (dir_info[selected].is_dir) - load_dir(); - else { - try_run_command_blocking(path_sz); - //TODO: handle error - path_sz[old_len] = '\0'; - path_len = old_len; - } - } - break; - case _KEY_ESC: - { - char *cutoff = path_sz; - for (char *i = path_sz + path_len - 1; i >= path_sz; --i) - if (*i == '/') { - cutoff = i; - break; - } - *cutoff = '\0'; - path_len = cutoff - path_sz; - load_dir(); - } - break; - case _KEY_HOME: - scroll = 0; - selected = 0; - break; - case _KEY_END: - selected = dir_info_len - 1; - scroll = dir_info_len >= MAX_PER_SCREEN - ? dir_info_len - MAX_PER_SCREEN : 0; - break; - case _KEY_UP: - if (!selected) - continue; - if (--selected < scroll) - scroll = selected; - break; - case _KEY_DOWN: - if (selected == dir_info_len - 1) - continue; - if (++selected >= scroll + MAX_PER_SCREEN) - ++scroll; - break; - case _KEY_PUP: - selected = selected >= MAX_PER_SCREEN - ? selected - MAX_PER_SCREEN : 0; - scroll = scroll >= MAX_PER_SCREEN - ? scroll - MAX_PER_SCREEN : 0; - break; - case _KEY_PDOWN: - if ((selected += MAX_PER_SCREEN) >= dir_info_len) - selected = dir_info_len - 1; - if ((scroll += MAX_PER_SCREEN) > selected) - scroll = selected; - break; - case 'q': - _clear_screen(); - return; - default: - continue; - } - paint_screen(); - } -} \ No newline at end of file diff --git a/src/user/hello/hello.asm b/src/user/hello/hello.asm deleted file mode 100644 index 65d32be..0000000 --- a/src/user/hello/hello.asm +++ /dev/null @@ -1,14 +0,0 @@ -bits 32 - -global _entry - -section .text -_entry: - mov eax, 0x5 - mov ebx, hello - int 0x30 - - int 0x38 - -section .data -hello db "Hello, world!", 0x0a, 0 \ No newline at end of file diff --git a/src/user/highway/cmds.c b/src/user/highway/cmds.c index d7a89d1..0420ae1 100644 --- a/src/user/highway/cmds.c +++ b/src/user/highway/cmds.c @@ -1,12 +1,16 @@ +#include + #include -#include + #include "line.h" #include "vars.h" void source(const char *path) { struct file *f = open_file(path); - if (!f) - tell_user_sz("couldn't open file.\n"); + if (!f) { + term_addf("Could not open %s.\n", path); + return; + } char buf[128]; while (read_line_from_file(f, buf, 127)) run_line(buf); diff --git a/src/user/highway/line.c b/src/user/highway/line.c index c8e5c60..bf171e5 100644 --- a/src/user/highway/line.c +++ b/src/user/highway/line.c @@ -1,19 +1,37 @@ -#include +#include + #include #include -#include + +#include + #include "cmds.h" +#include "term.h" #include "vars.h" #define LINE_SIZE 4096 static char line[LINE_SIZE]; +static inline uint8_t hex_to_int(char ch) { + return ch - (ch <= '9' ? '0' : 'a' - 10); +} + +void ensure_color() { + const struct no_null_sn *fg = get_var((struct no_null_sn){.data = "_color_fg", .length = 9}); + const struct no_null_sn *bg = get_var((struct no_null_sn){.data = "_color_bg", .length = 9}); + if (fg && bg) + set_color( + (hex_to_int(fg->data[0]) << 4) | hex_to_int(fg->data[1]), + (hex_to_int(bg->data[0]) << 4) | hex_to_int(bg->data[1]) + ); +} + static void line_replace(const char *from) { const char *fi = from; char *ti = line; while (*fi) { if (ti == line + LINE_SIZE) { - tell_user_sz("Line too long.\n"); + term_add_sz("Line too long.\n"); line[0] = '\0'; return; } @@ -27,12 +45,15 @@ static void line_replace(const char *from) { const char *var_end = var_start; while (*var_end != '$') if (!*var_end++) { - tell_user_sz("Unterminated variable name.\n"); + if (var_end - fi > 10) + term_addf("Unterminated variable at\"%10s...\".\n", fi); + else + term_addf("Unterminated variable at \"%s\".\n", fi); line[0] = '\0'; return; } if (ti + (var_end - var_start) >= line + LINE_SIZE) { - tell_user_sz("Line too long.\n"); + term_add_sz("Line too long.\n"); line[0] = '\0'; return; } @@ -59,46 +80,50 @@ void run_line(const char *original_line) { ; if (blockequ(line, "source ", 7)) source(space + 1); - else if (blockequ(line, "set ", 4)) + else if (blockequ(line, "set ", 4)) { set(space + 1); + ensure_color(); + } else if (blockequ(line, "echo ", 5)) { - tell_user_sz(space + 1); - tell_user_sz("\n"); + term_add_sz(space + 1); + term_add_char('\n'); } else if (blockequ(line, "vars", 5)) dump_vars(); - else if (blockequ(line, "quit", 5)) + else if (blockequ(line, "quit", 5)) { + del_term(active_term); __pcrt_quit(); + } else if (blockequ(line, "clear", 6)) - _clear_screen(); + clear_term(); else if (blockequ(line, "help", 5)) - tell_user_sz("Highway is a command shell for Portland OS. It includes variables and a couple\n" - "of pseudo-commands. Variables are addressed by surrounding with \"$\". The\n" - "following list shows each of the pseudo-commands.\n\n" - " source FILE run each command in FILE\n" - " clear clear the screen\n" - " echo STRING print STRING\n" - " set VAR VALUE set $VAR$ to VALUE\n" - " vars dump variables\n" - " quit exit highway\n" - " help show this\n"); - else if (!try_run_command_blocking(line)) { - struct no_null_sn arg = { - .data = "_path", - .length = 5 - }; - const struct no_null_sn *path = get_var(arg); + term_add_sz("Highway is a command shell for Portland OS. It includes variable support and a couple of pseudo-commands. Variables are addressed by surrounding with \"$\". The following list shows each of the pseudo-commands.\n\n" + " source FILE\t" "run each command in FILE\n" + " clear\t\t\t" "clear the screen\n" + " echo STRING\t" "print STRING\n" + " set VAR VALUE\t" "set $VAR$ to VALUE\n" + " vars\t\t\t" "dump variables\n" + " quit\t\t\t" "exit highway\n" + " help\t\t\t" "show this\n"); + else if (!try_run_command_blocking(line, stdio_task)) { + const struct no_null_sn *path = get_var((struct no_null_sn){.data = "_path", .length = 5}); if (!path->length) { - tell_user_sz("Could not run command.\n"); + term_add_sz("Could not run command.\n"); return; } for (uint16_t to_i = LINE_SIZE - 1; to_i >= path->length; --to_i) line[to_i] = line[to_i - path->length]; blockcpy(line, path->data, path->length); - if (!try_run_command_blocking(line)) { - tell_user_sz("Could not run command.\n"); + if (!try_run_command_blocking(line, stdio_task)) { + term_add_sz("Could not run command.\n"); return; } + else { + ensure_color(); + if (active_term->cursor_x) + term_newline(); + } } - _set_color(0x07); + else + ensure_color(); } \ No newline at end of file diff --git a/src/user/highway/line.h b/src/user/highway/line.h index 4785034..fc131ec 100644 --- a/src/user/highway/line.h +++ b/src/user/highway/line.h @@ -2,5 +2,6 @@ #define LINE_H void run_line(const char *line); +void ensure_color(); #endif \ No newline at end of file diff --git a/src/user/highway/main.c b/src/user/highway/main.c index 4599315..60d5a69 100644 --- a/src/user/highway/main.c +++ b/src/user/highway/main.c @@ -1,17 +1,36 @@ -#include +#include +#include + +#include + +#include +#include #include + #include "cmds.h" #include "line.h" +#define FONT_NAME "berry" + void main(const char *arg) { + struct font_info *f = get_font(FONT_NAME); + + if (!f) + return; + + active_term = make_term(f, 50, 18); + if (!active_term) + return; + source(*arg ? arg : "user/default.rc"); + ensure_color(); + + term_add_sz("Portland Highway\nType \"help\" for help.\n"); + paint_term(); + char cmd_buf[128]; - yield_task(); - struct history *cmd_hs = new_history(128); - tell_user_sz("Portland Highway\nType \"help\" for help.\n"); while (1) { - tell_user_sz("\n> "); - ask_user_line_sz_with_history(cmd_buf, 127, cmd_hs); + read_line(cmd_buf, 127, "> "); run_line(cmd_buf); } } \ No newline at end of file diff --git a/src/user/highway/vars.c b/src/user/highway/vars.c index 6090b76..5f56621 100644 --- a/src/user/highway/vars.c +++ b/src/user/highway/vars.c @@ -1,6 +1,10 @@ +#include + +#include #include #include -#include + +#include struct no_null_sn { char *data; @@ -73,26 +77,6 @@ void del_var(struct no_null_sn name) { void dump_vars() { for (struct var_dict_node *node = var_dict_start; node; node = node->next) { - tell_user_sz("$"); - - char *buf = get_block(node->name.length + 1); - blockcpy(buf, node->name.data, node->name.length); - buf[node->name.length] = '\0'; - - tell_user_sz(buf); - - free_block(buf); - - tell_user_sz("$ = "); - - buf = get_block(node->value.length + 1); - blockcpy(buf, node->value.data, node->value.length); - buf[node->value.length] = '\0'; - - tell_user_sz(buf); - - free_block(buf); - - tell_user_sz("\n"); + term_addf_no_ww("$%ns$ = %ns\n", node->name.length, node->name.data, node->value.length, node->value.data); } } \ No newline at end of file diff --git a/src/user/include/knob/block.h b/src/user/include/knob/block.h index 56d3740..f77709d 100644 --- a/src/user/include/knob/block.h +++ b/src/user/include/knob/block.h @@ -13,4 +13,9 @@ uint32_t strcpy(char *to, const char *from); //allocates new memory char *strdup(const char *from); +//without null-terminator +uint32_t strlen(const char *str) __attribute__ ((pure)); + +bool strequ(const char *a, const char *b) __attribute__ ((pure)); + #endif \ No newline at end of file diff --git a/src/user/include/knob/env.h b/src/user/include/knob/env.h deleted file mode 100644 index 6d750ae..0000000 --- a/src/user/include/knob/env.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef KNOB_ENV_H -#define KNOB_ENV_H - -#include - -//not implemented yet -extern uint32_t current_drive; - -#endif \ No newline at end of file diff --git a/src/user/include/knob/format.h b/src/user/include/knob/format.h index d55036c..fed31c7 100644 --- a/src/user/include/knob/format.h +++ b/src/user/include/knob/format.h @@ -1,12 +1,29 @@ #ifndef KNOB_FORMAT_H #define KNOB_FORMAT_H -#include +#include + #include +#include + +//allocates new memory +char *format_v(const char *fmt, va_list args); + +//allocates new memory +char *format(const char *fmt, ...); + +void syslogf_v(const char *fmt, va_list args); + +void syslogf(const char *fmt, ...); + +//reads a unsigned decimal terminated by either null or whitespace +//returns length of string plus length of whitespace +//returns 0 on failure +uint32_t try_swtou(const char *from, uint32_t *i_out); -bool try_sntoi(const char *s, uint32_t n, uint32_t *out); -void itosz(uint32_t i, char *out) __attribute__ ((access (write_only, 2))); -void itosz_h8(uint8_t i, char *out) __attribute__ ((access (write_only, 2))); -void itosz_h32(uint32_t i, char *out) __attribute__ ((access (write_only, 2))); +//reads a hexadecimal terminated by either null or whitespace +//returns length of string plus length of whitespace +//returns 0 on failure +uint32_t try_swtoh(const char *from, uint32_t *i_out); #endif \ No newline at end of file diff --git a/src/user/include/knob/ipc.h b/src/user/include/knob/ipc.h new file mode 100644 index 0000000..3eab562 --- /dev/null +++ b/src/user/include/knob/ipc.h @@ -0,0 +1,16 @@ +#ifndef KNOB_IPC_H +#define KNOB_IPC_H + +#include + +//blocking, returns early if other process is dead. +//return value is number of bytes written. +uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size); + +//blocking, returns early if other process is dead. +//return value is number of bytes read. +uint32_t try_read_ipc(_task_handle_t from, void *buffer, uint32_t size); + +void flush_ipc(_task_handle_t from); + +#endif \ No newline at end of file diff --git a/src/user/include/knob/key.h b/src/user/include/knob/key.h new file mode 100644 index 0000000..90509fc --- /dev/null +++ b/src/user/include/knob/key.h @@ -0,0 +1,8 @@ +#ifndef KNOB_KEY_H +#define KNOB_KEY_H + +#include + +char key_to_char(struct key_packet kp) __attribute__ ((pure)); + +#endif \ No newline at end of file diff --git a/src/user/include/knob/panic.h b/src/user/include/knob/panic.h new file mode 100644 index 0000000..1dd33a0 --- /dev/null +++ b/src/user/include/knob/panic.h @@ -0,0 +1,9 @@ +#ifndef KNOB_PANIC_H +#define KNOB_PANIC_H + +#include + +#define PANIC(msg) panic(__FILE__, __LINE__, msg) +void panic(const char *filename, uint32_t line, const char *message) __attribute__ ((noreturn)); + +#endif \ No newline at end of file diff --git a/src/user/include/knob/task.h b/src/user/include/knob/task.h index 6539a00..cd51c37 100644 --- a/src/user/include/knob/task.h +++ b/src/user/include/knob/task.h @@ -1,11 +1,12 @@ #ifndef KNOB_TASK_H #define KNOB_TASK_H +#include + #include #include -uint32_t run_command(const char *path); -bool try_run_command_blocking(const char *path); -void yield_task(); +uint32_t run_command(const char *path, _task_handle_t stdio_task); +bool try_run_command_blocking(const char *path, _task_handle_t stdio_task); #endif \ No newline at end of file diff --git a/src/user/include/knob/user.h b/src/user/include/knob/user.h deleted file mode 100644 index fb11c9b..0000000 --- a/src/user/include/knob/user.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef KNOB_USER_H -#define KNOB_USER_H - -#include -#include - -struct history; - -char key_to_char(_key_code_t key) __attribute__ ((const)); - -void tell_user_sz(const char *sz); - -//return value and max_length don't include null terminator -//returns the real length of the string -uint32_t ask_user_line_sz(char *sz, uint32_t max_length); - -struct history *new_history(uint32_t max_entries); -void del_history(struct history *hs); - -uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs); - -#endif \ No newline at end of file diff --git a/src/user/include/libfont/fonts.h b/src/user/include/libfont/fonts.h new file mode 100644 index 0000000..b66659f --- /dev/null +++ b/src/user/include/libfont/fonts.h @@ -0,0 +1,21 @@ +#ifndef LIBFONT_FONTS_H +#define LIBFONT_FONTS_H + +#include +#include + +struct font_info { + uint32_t space_width; + uint32_t space_height; + uint32_t char_width; + uint32_t char_height; + bool *bitmaps[256];//left to right then top to bottom + //null pointer for unsupported character + //unsupported characters drawn as bitmaps[0] +}; + +struct font_info *get_font(const char *name); + +void put_char(const struct font_info *font, char ch, uint8_t *pb_ptr, uint32_t pb_pitch, uint8_t bg, uint8_t fg); + +#endif \ No newline at end of file diff --git a/src/user/include/pland/pcrt.h b/src/user/include/pland/pcrt.h index 07ad453..42158cd 100644 --- a/src/user/include/pland/pcrt.h +++ b/src/user/include/pland/pcrt.h @@ -1,6 +1,8 @@ #ifndef PLAND_PCRT_H #define PLAND_PCRT_H +#include + #define BEFORE_MAIN(f) \ __attribute__ ((section (".__pcrt_before_main"))) \ __attribute__ ((unused)) \ @@ -13,4 +15,7 @@ void __pcrt_quit() __attribute__ ((noreturn)); -#endif \ No newline at end of file +extern _task_handle_t calling_task; +extern _task_handle_t stdio_task; + +#endif diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h index ead5fea..6d327d5 100644 --- a/src/user/include/pland/syscall.h +++ b/src/user/include/pland/syscall.h @@ -4,119 +4,12 @@ #include #include +#include + typedef uint32_t _file_handle_t; typedef uint32_t _task_handle_t; typedef uint32_t _drive_number_t; -typedef uint32_t _process_handle_t; - -typedef enum { - _KEY_LSHIFT = 0x00000100, - _KEY_RSHIFT = 0x00000200, - _KEY_CAPS = 0x00000400, - _KEY_INSERT = 0x00000800, - _KEY_NUM = 0x00001000, - _KEY_SCROLL = 0x00002000, - _KEY_LALT = 0x00004000, - _KEY_RALT = 0x00008000, - _KEY_LCTRL = 0x00010000, - _KEY_RCTRL = 0x00020000, - _KEY_LMETA = 0x00040000, - _KEY_RMETA = 0x00080000, - - _KEY_SHIFT = 0x00000300, - _KEY_SCAPS = 0x00000700, - _KEY_ALT = 0x0000c000, - _KEY_CTRL = 0x00030000, - _KEY_META = 0x000c0000, - - _KEY_BEGIN_CAPS = 0x80, - _KEY_BEGIN_INSERT, - _KEY_BEGIN_NUM, - _KEY_BEGIN_SCROLL, - _KEY_BEGIN_LSHIFT, - _KEY_BEGIN_RSHIFT, - _KEY_BEGIN_LALT, - _KEY_BEGIN_RALT, - _KEY_BEGIN_LCTRL, - _KEY_BEGIN_RCTRL, - _KEY_BEGIN_LMETA, - _KEY_BEGIN_RMETA, - /* 0x8c - 0x97 reserved */ - /* 0x98 - 0x9f unassigned */ - _KEY_F1 = 0xa0, - _KEY_F2, - _KEY_F3, - _KEY_F4, - _KEY_F5, - _KEY_F6, - _KEY_F7, - _KEY_F8, - _KEY_F9, - _KEY_F10, - _KEY_F11, - _KEY_F12, - /* 0xac - 0xaf unassigned */ - _KEY_NUM0 = 0xb0, - _KEY_NUM1, - _KEY_NUM2, - _KEY_NUM3, - _KEY_NUM4, - _KEY_NUM5, - _KEY_NUM6, - _KEY_NUM7, - _KEY_NUM8, - _KEY_NUM9, - _KEY_NTIMES, - _KEY_NPLUS, - _KEY_NENTER, - _KEY_NMINUS, - _KEY_NDOT, - _KEY_NSLASH, - /* 0xc0 unassigned */ - _KEY_DELETE = 0xc1, - _KEY_HOME, - _KEY_END, - _KEY_PUP, - _KEY_PDOWN, - _KEY_UP, - _KEY_DOWN, - _KEY_LEFT, - _KEY_RIGHT, - _KEY_ESC, - _KEY_MENU, - _KEY_PAUSE, - _KEY_PRSCR, - /* 0xce - 0xef unassigned */ -} _key_code_t; - -typedef enum { - _COLOR_FG_BLACK = 0x00, - _COLOR_FG_BLUE = 0x01, - _COLOR_FG_GREEN = 0x02, - _COLOR_FG_CYAN = 0x03, - _COLOR_FG_RED = 0x04, - _COLOR_FG_MAGENTA = 0x05, - _COLOR_FG_BROWN = 0x06, - _COLOR_FG_LGRAY = 0x07, - - _COLOR_FG_DGRAY = 0x08, - _COLOR_FG_LBLUE = 0x09, - _COLOR_FG_LGREEN = 0x0a, - _COLOR_FG_LCYAN = 0x0b, - _COLOR_FG_LRED = 0x0c, - _COLOR_FG_PINK = 0x0d, - _COLOR_FG_YELLOW = 0x0e, - _COLOR_FG_WHITE = 0x0f, - - _COLOR_BG_BLACK = 0x00, - _COLOR_BG_BLUE = 0x10, - _COLOR_BG_GREEN = 0x20, - _COLOR_BG_CYAN = 0x30, - _COLOR_BG_RED = 0x40, - _COLOR_BG_MAGENTA = 0x50, - _COLOR_BG_BROWN = 0x60, - _COLOR_BG_LGRAY = 0x70 -} _vga_color_t; +typedef void *_window_handle_t; typedef struct __attribute__ ((packed)) { char name[100]; @@ -131,17 +24,26 @@ enum _scn { _SCN_FILE_READ, _SCN_FILE_SIZE, _SCN_START_TASK, - _SCN_LOG_STRING, - _SCN_GET_KEY, + _SCN_IPC_SEND, + _SCN_IPC_READ, _SCN_ALLOCATE_RAM, _SCN_MEMORY_INFO, _SCN_WAIT_FOR_TASK, _SCN_ENUMERATE_DIR, - _SCN_PRINT_AT, + _SCN_SYSTEM_LOG, _SCN_COUNT_OF_DIR, - _SCN_CLEAR_SCREEN, - _SCN_SET_COLOR, - _SCN_SWAP_COLOR + _SCN_NEW_WINDOW, + _SCN_DELETE_WINDOW, + _SCN_RESIZE_WINDOW, + _SCN_REASSIGN_PIXBUF, + _SCN_PAINT_WINDOW, + _SCN_GET_WIN_ACTION, + _SCN_WAIT_FOR_ACTION, + _SCN_WAIT_IPC_SEND, + _SCN_WAIT_FOR_ANY_IPC, + _SCN_FIND_UNREAD_IPC, + _SCN_WAIT_IPC_READ, + _SCN_IS_TASK_RUNNING }; static inline uint32_t _sc0(enum _scn eax) { @@ -211,7 +113,7 @@ static inline void _exit_task() { } static inline _file_handle_t _open_file(_drive_number_t drive_number, const char *path) { - return _sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path); + return (_file_handle_t)_sc2(_SCN_OPEN_FILE, drive_number, (uint32_t)path); } static inline void _close_file(_file_handle_t handle) { @@ -226,16 +128,16 @@ static inline uint32_t _file_size(_file_handle_t handle) { return _sc1(_SCN_FILE_SIZE, handle); } -static inline _process_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass) { - return _sc3(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass); +static inline _task_handle_t _start_task(_drive_number_t drive_number, const char *path, const char *pass, _task_handle_t stdio_task) { + return (_task_handle_t)_sc4(_SCN_START_TASK, drive_number, (uint32_t)path, (uint32_t)pass, (uint32_t)stdio_task); } -static inline void _log_string(const char *sz) { - _sc1(_SCN_LOG_STRING, (uint32_t)sz); +static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const void *buffer) { + return _sc3(_SCN_IPC_SEND, handle, count, (uint32_t)buffer); } -static inline _key_code_t _get_key() { - return _sc0(_SCN_GET_KEY); +static inline uint32_t _ipc_read(_task_handle_t handle, uint32_t count, void *buffer) { + return _sc3(_SCN_IPC_SEND, handle, count, (uint32_t)buffer); } static inline void *_allocate_ram(uint32_t pages) { @@ -262,7 +164,7 @@ static inline uint32_t _this_process_memory_left() { return _sc1(_SCN_MEMORY_INFO, 0x4); } -static inline void _wait_for_task(_process_handle_t handle) { +static inline void _wait_for_task(_task_handle_t handle) { _sc1(_SCN_WAIT_FOR_TASK, handle); } @@ -270,24 +172,60 @@ static inline uint32_t _enumerate_dir(_drive_number_t drive_number, const char * return _sc4(_SCN_ENUMERATE_DIR, drive_number, (uint32_t)path, (uint32_t)buffer, max_count); } -static inline void _print_at(uint8_t row, uint8_t col, const char *sz) { - _sc2(_SCN_PRINT_AT, (row << 8) | col, (uint32_t)sz); -} - static inline uint32_t _count_of_dir(uint8_t drive_number, const char *path) { return _sc2(_SCN_COUNT_OF_DIR, drive_number, (uint32_t)path); } -static inline void _clear_screen() { - _sc0(_SCN_CLEAR_SCREEN); +static inline _window_handle_t _new_window(uint16_t width, uint16_t height, void *pixel_buffer) { + return (_window_handle_t)_sc3(_SCN_NEW_WINDOW, width, height, (uint32_t)pixel_buffer); +} + +static inline void _delete_window(_window_handle_t window) { + _sc1(_SCN_DELETE_WINDOW, (uint32_t)window); +} + +static inline void _resize_window(_window_handle_t window, uint16_t width, uint16_t height) { + _sc3(_SCN_RESIZE_WINDOW, (uint32_t)window, width, height); +} + +static inline void _reassign_pixbuf(_window_handle_t window, void *pixel_buffer) { + _sc2(_SCN_REASSIGN_PIXBUF, (uint32_t)window, (uint32_t)pixel_buffer); +} + +static inline void _paint_window(_window_handle_t window) { + _sc1(_SCN_PAINT_WINDOW, (uint32_t)window); +} + +static inline void _get_win_action(_window_handle_t window, struct window_action *action_pointer) { + _sc2(_SCN_GET_WIN_ACTION, (uint32_t)window, (uint32_t)action_pointer); +} + +static inline void _wait_for_action() { + _sc0(_SCN_WAIT_FOR_ACTION); +} + +static inline void _wait_ipc_send(_task_handle_t sending_task) { + _sc1(_SCN_WAIT_IPC_SEND, sending_task); +} + +static inline void _system_log(const char *sz) { + _sc1(_SCN_SYSTEM_LOG, (uint32_t)sz); +} + +static inline void _wait_for_any_ipc() { + _sc0(_SCN_WAIT_FOR_ANY_IPC); +} + +static inline _task_handle_t _find_unread_ipc() { + return _sc0(_SCN_FIND_UNREAD_IPC); } -static inline void _set_color(_vga_color_t color) { - _sc1(_SCN_SET_COLOR, color); +static inline void _wait_ipc_read(_task_handle_t reading_task) { + _sc1(_SCN_WAIT_IPC_READ, reading_task); } -static inline void _swap_color(uint8_t row, uint8_t col) { - _sc1(_SCN_SWAP_COLOR, (row << 8) | col); +static inline bool _is_task_running(_task_handle_t handle) { + return (bool)_sc1(_SCN_IS_TASK_RUNNING, handle); } #endif \ No newline at end of file diff --git a/src/user/include/popups/info.h b/src/user/include/popups/info.h new file mode 100644 index 0000000..2c4e83f --- /dev/null +++ b/src/user/include/popups/info.h @@ -0,0 +1,14 @@ +#ifndef POPUPS_INFO_H +#define POPUPS_INFO_H + +#include + +#include + +#include + +void info_popup(struct popup *into, const char *text, uint8_t fg, uint8_t bg); +void info_popupf(struct popup *into, const char *text, uint8_t fg, uint8_t bg, ...); +void info_popupf_v(struct popup *into, const char *text, uint8_t fg, uint8_t bg, va_list args); + +#endif \ No newline at end of file diff --git a/src/user/include/popups/popup.h b/src/user/include/popups/popup.h new file mode 100644 index 0000000..1a3c531 --- /dev/null +++ b/src/user/include/popups/popup.h @@ -0,0 +1,23 @@ +#ifndef POPUPS_POPUP_H +#define POPUPS_POPUP_H + +#include + +struct popup { + _window_handle_t handle; + uint8_t *pixbuf; + + bool has_quit; + struct key_packet quit_as; + + //terminated by one with .key_id == 0 + struct key_packet *quit_binds; + bool free_quit_binds; +}; + +void handle_actions(struct popup *p); +//deletes popup before returning +void make_modal(struct popup *p); +void delete_popup(struct popup *p); + +#endif \ No newline at end of file diff --git a/src/user/include/terminal/readline.h b/src/user/include/terminal/readline.h new file mode 100644 index 0000000..9046610 --- /dev/null +++ b/src/user/include/terminal/readline.h @@ -0,0 +1,10 @@ +#ifndef TERMINAL_READLINE_H +#define TERMINAL_READLINE_H + +#include + +//returns length of string without null terminator +//max_length doesn't include null terminator +uint32_t read_line(char *sz, uint32_t max_length, const char *prompt); + +#endif \ No newline at end of file diff --git a/src/user/include/terminal/terminal.h b/src/user/include/terminal/terminal.h new file mode 100644 index 0000000..1782173 --- /dev/null +++ b/src/user/include/terminal/terminal.h @@ -0,0 +1,57 @@ +#ifndef TERMINAL_TERMINAL_H +#define TERMINAL_TERMINAL_H + +#include + +#include + +#include +#include + +struct terminal { + _window_handle_t window; + uint8_t *pixbuf; + uint32_t window_width; + uint32_t window_height; + + struct font_info *font; + + uint32_t cols; + uint32_t rows; + char *charbuf; + + uint32_t cursor_y; + uint32_t cursor_x; + + uint8_t fg; + uint8_t bg; +}; + +struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows); +void del_term(struct terminal *term); + +extern struct terminal *active_term; + +void paint_term(); + +void set_color(uint8_t fg, uint8_t bg); +void clear_term(); + +void move_cursor(uint32_t new_y, uint32_t new_x); + +void cursor_left(); +void cursor_right(); +void cursor_up(); +void cursor_down(); + +void term_newline(); +void term_add_char(char ch); +void term_add_sz_no_ww(const char *sz); +void term_add_sz(const char *sz); + +void term_addf_no_ww_v(const char *fmt, va_list args); +void term_addf_no_ww(const char *fmt, ...); +void term_addf_v(const char *fmt, va_list args); +void term_addf(const char *fmt, ...); + +#endif \ No newline at end of file diff --git a/src/user/init/init.c b/src/user/init/init.c index fb231e0..860c45f 100644 --- a/src/user/init/init.c +++ b/src/user/init/init.c @@ -1,32 +1,29 @@ -#include #include #include #define STARTUP_FILE_PATH "sys/startup.rc" +#define CMD_BUF_LEN 1024 + +char cmdbuf[CMD_BUF_LEN]; void main() { struct file *f = open_file(STARTUP_FILE_PATH); if (!f) { - tell_user_sz("Could not open " STARTUP_FILE_PATH ".\n"); + _system_log("Could not open " STARTUP_FILE_PATH ".\n"); return; } - tell_user_sz("[init] Reading from " STARTUP_FILE_PATH ".\n"); - - char cmdbuf[128]; - while (read_line_from_file(f, cmdbuf, 127)) { - tell_user_sz("[init] Starting "); - tell_user_sz(cmdbuf); - tell_user_sz(": "); - if (run_command(cmdbuf)) { - tell_user_sz("Succeded.\n"); - yield_task(); - } - else - tell_user_sz("Failed.\n"); + while (read_line_from_file(f, cmdbuf, CMD_BUF_LEN - 1)) { + if (cmdbuf[0] == '#') + continue; + //syslogf(run_command(cmdbuf) + // ? "[init] Started %s." + // : "[init] Could not run %s." + //, cmdbuf); + run_command(cmdbuf, 0); } close_file(f); - tell_user_sz("[init] Done starting programs.\n"); + _system_log("Done starting startup tasks."); } diff --git a/src/user/knob/block.c b/src/user/knob/block.c index 94bd073..90f79e3 100644 --- a/src/user/knob/block.c +++ b/src/user/knob/block.c @@ -33,4 +33,28 @@ char *strdup(const char *from) { char *buf = get_block(end - from); blockcpy(buf, from, end - from); return buf; +} + +__attribute__ ((pure)) +bool strequ(const char *a, const char *b) { + while (true) { + if ((*a == '\0') != (*b == '\0')) + return false; + if (*a == '\0') + return true; + if (*a != *b) + return false; + ++a; + ++b; + } +} + +__attribute__ ((pure)) +uint32_t strlen(const char *str) { + uint32_t len = 0; + while (*str) { + ++len; + ++str; + } + return len; } \ No newline at end of file diff --git a/src/user/knob/env.c b/src/user/knob/env.c deleted file mode 100644 index 952ab86..0000000 --- a/src/user/knob/env.c +++ /dev/null @@ -1,3 +0,0 @@ -#include - -uint32_t current_drive; \ No newline at end of file diff --git a/src/user/knob/file.c b/src/user/knob/file.c index f1a039d..3083503 100644 --- a/src/user/knob/file.c +++ b/src/user/knob/file.c @@ -1,8 +1,9 @@ -#include -#include #include +#include #include -#include + +#include +#include struct ofl_node { struct ofl_node *next; @@ -27,23 +28,10 @@ struct file { }; const char *remove_prefix(const char *path, uint8_t *dn_out) { - if ((path[0] != 's') || (path[1] != 'd')) - goto no_prefix; - - const char *num_part = path + 2; - for (uint32_t i = 0; num_part[i]; ++i) - if (num_part[i] == ':') { - - uint32_t dn_large; - if (!try_sntoi(num_part, i, &dn_large) || dn_large > 255) - goto no_prefix; - - *dn_out = (uint8_t)dn_large; - return num_part + i + 1; - } + if ((path[0] == 's') && (path[1] == 'd')) + PANIC("remove_prefix not fully implemented"); -no_prefix: - *dn_out = current_drive; + *dn_out = 0;//change this later to an "active drive" or something return path; } diff --git a/src/user/knob/format.c b/src/user/knob/format.c index 593b20c..54d50ef 100644 --- a/src/user/knob/format.c +++ b/src/user/knob/format.c @@ -1,48 +1,231 @@ -#include -#include - -bool try_sntoi(const char *s, uint32_t n, uint32_t *out) { - uint32_t calc = 0; - for (uint32_t i = 0; i < n; ++i) { - if ((s[i] < '0') || (s[i] > '9')) - return false; - calc = calc * 10 + s[i] - '0'; - } - *out = calc; - return true; -} +#include +#include +#include + +#include +#include + +#include + +#define FORMAT_BUF_INIT_SIZE 200 +#define FORMAT_BUF_CHUNK_SIZE 50 -__attribute__ ((access (write_only, 2))) -void itosz(uint32_t i, char *out) { - if (!i) { - *(uint16_t *)out = (uint16_t)'0'; +#define BAD_SPEC "%%UNKNOWN FORMAT SPEC%%" +#define BAD_SPEC_LEN 23 + +static char *buf; +static uint32_t buf_s; +static char *buf_i; + +static const char *const hextab = "0123456789abcdef"; + +static void ensure(uint32_t extra) { + const uint32_t total_len = buf_i - buf + extra; + if (total_len < buf_s) return; + + buf_s = (total_len / FORMAT_BUF_CHUNK_SIZE + 1) * FORMAT_BUF_CHUNK_SIZE; + + char *const new_buf = get_block(buf_s); + if (!new_buf) + PANIC("out of memory in knob format"); + blockcpy(new_buf, buf, buf_i - buf); + free_block(buf); + buf_i += new_buf - buf; + buf = new_buf; +} + +struct format_spec { + uint32_t len; + enum { + UNKNOWN, + CHAR, + STRING, + UNSIGNED_DECIMAL, + HEXADECIMAL + //TODO: signed decimal + } kind; +}; + +static const char *get_format(const char *from, struct format_spec *format_out) { + if (*from == 'n') { + ++from; + format_out->len = -1; } - bool zero = false; - for (uint32_t m = 1000000000; m; m /= 10) { - uint8_t d = (i / m) % 10; - if (zero) - *(out++) = d + '0'; - else if (d) { - zero = true; - *(out++) = d + '0'; + else { + uint32_t len = 0; + while ((*from >= '0') && (*from <= '9')) + len = len * 10 + *(from++) - '0'; + format_out->len = len; + } + + switch (*from) { + case 'c': + format_out->kind = CHAR; + break; + case 's': + format_out->kind = STRING; + break; + case 'u': + format_out->kind = UNSIGNED_DECIMAL; + break; + case 'h': + case 'x': + format_out->kind = HEXADECIMAL; + break; + default: + format_out->kind = UNKNOWN; + break; + } + + return from + 1; +} + +//allocates new memory +char *format_v(const char *fmt, va_list args) { + buf = get_block(FORMAT_BUF_INIT_SIZE); + if (!buf) + PANIC("out of memory in knob format"); + buf_s = FORMAT_BUF_INIT_SIZE; + buf_i = buf; + + while (*fmt) { + if (*fmt != '%') { + ensure(1); + *(buf_i++) = *(fmt++); + } + else if (fmt[1] == '%') { + ensure(1); + *(buf_i++) = '%'; + fmt += 2; + } + else { + struct format_spec form; + fmt = get_format(fmt + 1, &form); + if (form.len == -1) + //should passing zero still have the special meaning? + form.len = va_arg(args, uint32_t); + switch (form.kind) { + case UNKNOWN: + ensure(BAD_SPEC_LEN); + blockcpy(buf_i, BAD_SPEC, BAD_SPEC_LEN); + buf_i += BAD_SPEC_LEN; + continue; + + uint32_t ch; + case CHAR: + ch = va_arg(args, uint32_t); + ensure(1); + *(buf_i++) = (char)ch; + continue; + + const char *str; + case STRING: + str = va_arg(args, const char *); + if (!form.len) + form.len = strlen(str); + ensure(form.len); + blockcpy(buf_i, str, form.len); + buf_i += form.len; + continue; + + uint32_t k; + case UNSIGNED_DECIMAL: + k = va_arg(args, uint32_t); + if (!form.len) { + uint32_t n = 10; + ++form.len; + while (k >= n) { + ++form.len; + n *= 10; + } + } + ensure(form.len); + const uint32_t len_backup = form.len; + while (form.len--) { + buf_i[form.len] = (k % 10) + '0'; + k /= 10; + } + buf_i += len_backup; + continue; + + case HEXADECIMAL: + k = va_arg(args, uint32_t); + if (!form.len) + form.len = 8; + ensure(form.len); + const uint32_t hlen_backup = form.len; + while (form.len--) { + buf_i[form.len] = hextab[k % 16]; + k >>= 4; + } + buf_i += hlen_backup; + continue; + } } } - *out = '\0'; + + *buf_i = '\0'; + return buf; +} + +//allocates new memory +char *format(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + char *const res = format_v(fmt, args); + va_end(args); + return res; +} + +void syslogf_v(const char *fmt, va_list args) { + char *const msg = format_v(fmt, args); + _system_log(msg); + free_block(msg); } -const char *const hex_digits = "0123456789abcdef"; +void syslogf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + syslogf_v(fmt, args); + va_end(args); +} -__attribute__ ((access (write_only, 2))) -void itosz_h8(uint8_t i, char *out) { - out[0] = hex_digits[i >> 4]; - out[1] = hex_digits[i & 0xf]; - out[2] = '\0'; +//reads a unsigned decimal terminated by either null or whitespace +//returns length of string plus length of whitespace +//returns 0 on failure +uint32_t try_swtou(const char *from, uint32_t *i_out) { + const char *const old_from = from; + uint32_t v = 0; + while (*from && (*from != '\n') && (*from != ' ')) { + if ((*from < '0') || (*from > '9')) + return 0; + v = v * 10 + *(from++) - '0'; + } + *i_out = v; + while ((*from == '\n') || (*from == ' ')) + ++from; + return from - old_from; } -__attribute__ ((access (write_only, 2))) -void itosz_h32(uint32_t i, char *out) { - for (uint8_t digit = 0; digit < 8; ++digit) - out[digit] = hex_digits[(i >> (28 - digit * 4)) & 0xf]; - out[8] = '\0'; +//reads a hexadecimal terminated by either null or whitespace +//returns length of string plus length of whitespace +//returns 0 on failure +uint32_t try_swtoh(const char *from, uint32_t *i_out) { + const char *const old_from = from; + uint32_t v = 0; + while (*from && (*from != '\n') && (*from != ' ')) { + if ((*from >= '0') && (*from <= '9')) + v = v * 16 + *(from++) - '0'; + else if ((*from >= 'a') && (*from <= 'f')) + v = v * 16 + *(from++) - 'a' + 10; + else if ((*from >= 'A') && (*from <= 'F')) + v = v * 16 + *(from++) - 'A' + 10; + else + return 0; + } + *i_out = v; + while ((*from == '\n') || (*from == ' ')) + ++from; + return from - old_from; } \ No newline at end of file diff --git a/src/user/knob/heap.c b/src/user/knob/heap.c index 49f9339..b770542 100644 --- a/src/user/knob/heap.c +++ b/src/user/knob/heap.c @@ -1,4 +1,7 @@ +#include + #include + #include #include @@ -24,23 +27,8 @@ static void add_header(struct block_header *bh) { __attribute__ ((malloc)) void *get_block(uint32_t bytes) { -//char nbuf[11]; -//tell_user_sz("[heap::get_block]\n first_block = 0x"); -//itosz_h32((uint32_t)first_block, nbuf); -//tell_user_sz(nbuf); -//tell_user_sz("\n"); struct block_header *header = 0; - for (struct block_header *ptr = first_block; ptr; ptr = ptr->next) { - //tell_user_sz(" ptr = 0x"); - //itosz_h32((uint32_t)ptr, nbuf); - //tell_user_sz(nbuf); - //tell_user_sz("\n &ptr->allocated = 0x"); - //itosz_h32((uint32_t)&ptr->allocated, nbuf); - //tell_user_sz(nbuf); - //tell_user_sz("\n ptr->allocated = "); - //tell_user_sz(ptr->allocated ? "true\n" : "false\n"); - if (ptr->allocated) continue; if (ptr->length == bytes) { @@ -63,14 +51,7 @@ void *get_block(uint32_t bytes) { if (!header) { uint32_t size_with_header = bytes + sizeof(struct block_header); if (!(size_with_header % 4096)) { - //tell_user_sz(" allocate "); - //itosz(size_with_header / 4096, nbuf); - //tell_user_sz(nbuf); - //tell_user_sz(" pages = 0x"); header = _allocate_ram(size_with_header / 4096); - //itosz_h32((uint32_t)header, nbuf); - //tell_user_sz(nbuf); - //tell_user_sz("\n"); if (!header) return 0; header->length = bytes; @@ -78,14 +59,7 @@ void *get_block(uint32_t bytes) { } else { uint32_t pages = (bytes + sizeof(struct block_header) * 2) / 4096 + 1; - //tell_user_sz(" allocate "); - //itosz(pages, nbuf); - //tell_user_sz(nbuf); - //tell_user_sz(" pages = 0x"); header = _allocate_ram(pages); - //itosz_h32((uint32_t)header, nbuf); - //tell_user_sz(nbuf); - //tell_user_sz("\n"); if (!header) return 0; header->length = bytes; diff --git a/src/user/knob/ipc.c b/src/user/knob/ipc.c new file mode 100644 index 0000000..dbf1a22 --- /dev/null +++ b/src/user/knob/ipc.c @@ -0,0 +1,45 @@ +#include + +//blocking, returns early if other process is dead. +//return value is number of bytes written. +uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size) { + const uint32_t size_backup = size; + while (size) { + uint32_t res = _ipc_send(to, size, buffer); + if (!res) { + _wait_ipc_read(to); + _yield_task(); + } + else if (res == -1) + return size_backup - size; + else { + size -= res; + buffer += res; + } + } +} + +//blocking, returns early if other process is dead. +//return value is number of bytes read. +uint32_t read_ipc(_task_handle_t from, void *buffer, uint32_t size) { + const uint32_t size_backup = size; + while (size) { + uint32_t res = _ipc_read(from, size, buffer); + if (!res) { + _wait_ipc_send(from); + _yield_task(); + } + else if (res == -1) + return size_backup - size; + else { + size -= res; + buffer += res; + } + } +} + +void flush_ipc(_task_handle_t from) { + uint8_t buf[4096]; + while (_ipc_read(from, 4096, buf)) + ; +} \ No newline at end of file diff --git a/src/user/knob/key.c b/src/user/knob/key.c new file mode 100644 index 0000000..1506f3b --- /dev/null +++ b/src/user/knob/key.c @@ -0,0 +1,67 @@ +#include + +static const char no_mod[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ' ', 0, 0, 0, 0, 0, 0, '\'', 0, 0, 0, 0, ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, ';', 0, '=', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\', ']', 0, 0, + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 +}; + +static const char shifted[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ' ', 0, 0, 0, 0, 0, 0, '"', 0, 0, 0, 0, '<', '_', '>', '?', + ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 0, ':', 0, '+', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '{', '|', '}', 0, 0, + '~', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0 +}; + +static const char caps[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ' ', 0, 0, 0, 0, 0, 0, '\'', 0, 0, 0, 0, ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, ';', 0, '=', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '[','\\', ']', 0, 0, + '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 0, 0, 0, 0, 0 +}; + +static const char sh_caps[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, '\t','\n', 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ' ', 0, 0, 0, 0, 0, 0, '"', 0, 0, 0, 0, '<', '_', '>', '?', + ')', '!', '@', '#', '$', '%', '^', '&', '*', '(', 0, ':', 0, '+', 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '{', '|', '}', 0, 0, + '~', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 0, 0, 0, 0, 0 +}; + +static const char num[] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '+', '\n', '-', '.', '/' +}; + +__attribute__ ((pure)) +char key_to_char(struct key_packet kp) { + if (kp.key_id < 0x80) { + const char ch = (kp.modifiers & SHIFTS + ? kp.modifiers & CAPS + ? sh_caps : shifted + : kp.modifiers & CAPS + ? caps : no_mod)[kp.key_id]; + return ch ? kp.modifiers & ALTS ? 0x80 & ch : ch : 0; + } + + else if ((kp.modifiers & NUM) && ((kp.key_id & 0xf0) == 0xb0)) + return num[kp.key_id & 0x0f]; + + else + return 0; +} \ No newline at end of file diff --git a/src/user/knob/panic.c b/src/user/knob/panic.c new file mode 100644 index 0000000..1ff663c --- /dev/null +++ b/src/user/knob/panic.c @@ -0,0 +1,12 @@ +#include + +#include +#include + +#include + +__attribute__ ((noreturn)) +void panic(const char *filename, uint32_t line, const char *message) { + _system_log(format("panic in %s on line %u: %s", filename, line, message)); + __pcrt_quit(); +} \ No newline at end of file diff --git a/src/user/knob/task.c b/src/user/knob/task.c index df5d38f..3bf3e85 100644 --- a/src/user/knob/task.c +++ b/src/user/knob/task.c @@ -4,7 +4,7 @@ #include #include -_task_handle_t run_command(const char *path) { +_task_handle_t run_command(const char *path, _task_handle_t stdio_task) { uint8_t dn; path = remove_prefix(path, &dn); @@ -14,23 +14,21 @@ _task_handle_t run_command(const char *path) { blockcpy(new_path, path, ptr - path); new_path[ptr - path] = '\0'; - bool succeded = _start_task(dn, new_path, ptr + 1); + bool succeded = _start_task(dn, new_path, ptr + 1, stdio_task); free_block(new_path); return succeded; } - return _start_task(dn, path, ""); + return _start_task(dn, path, "", stdio_task); } -bool try_run_command_blocking(const char *path) { - _task_handle_t handle = run_command(path); +bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) { + _task_handle_t handle = run_command(path, stdio_task); if (!handle) return false; - _wait_for_task(handle); - _yield_task(); + while (_is_task_running(handle)) { + _wait_for_task(handle); + _yield_task(); + } return true; -} - -void yield_task() { - _yield_task(); } \ No newline at end of file diff --git a/src/user/knob/user.c b/src/user/knob/user.c deleted file mode 100644 index 1e273bb..0000000 --- a/src/user/knob/user.c +++ /dev/null @@ -1,299 +0,0 @@ -#include -#include -#include -#include -#include - -static const uint8_t caps_and_shift[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x22, - 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x5f, 0x3e, 0x3f, - 0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26, - 0x2a, 0x28, 0x3a, 0x3a, 0x3c, 0x2d, 0x3e, 0x3f, - - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x57, 0x7c, 0x7d, 0x5e, 0x5f, - 0x7e, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const uint8_t caps_no_shift[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -static const uint8_t shifted[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x22, - 0x28, 0x29, 0x2a, 0x2b, 0x3c, 0x5f, 0x3e, 0x3f, - 0x29, 0x21, 0x40, 0x23, 0x24, 0x25, 0x5e, 0x26, - 0x2a, 0x28, 0x3a, 0x3a, 0x3c, 0x2d, 0x3e, 0x3f, - - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x57, 0x7c, 0x7d, 0x5e, 0x5f, - 0x7e, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -__attribute__ ((const)) -char key_to_char(_key_code_t key) { - return - key & _KEY_CAPS - ? key & _KEY_SHIFT - ? caps_and_shift[key & 0xff] - : caps_no_shift[key & 0xff] - : key & _KEY_SHIFT - ? shifted[key & 0xff] - : key & 0xff; -} - -static char get_key_char() { - _key_code_t key; - while (!(key = _get_key())) - _yield_task(); - return key_to_char(key); -} - -void tell_user_sz(const char *sz) { - _log_string(sz); -} - -//return value and max_length don't include null terminator -uint32_t ask_user_line_sz(char *sz, uint32_t max_length) { - char log_buf[2]; - log_buf[1] = '\0'; - - uint32_t i; - for (i = 0; i != max_length; ++i) { - char key; - replace: - key = get_key_char(); - if (!key) - goto replace; - if (key & 0x80) - goto replace;//TODO - if (key == '\b') { - if (i) { - --i; - _log_string("\b"); - } - goto replace; - } - - log_buf[0] = key; - _log_string(log_buf); - - if (key == '\n') - break; - sz[i] = key; - } - - sz[i] = '\0'; - return i; -} - -struct history_entry { - struct history_entry *prev; - struct history_entry *next; - const char *contents; -}; - -struct history { - struct history_entry *earliest_history_item; - struct history_entry *latest_history_item; - uint32_t max_entries; - uint32_t cur_entries; -}; - -struct history *new_history(uint32_t max_entries) { - struct history *new = get_block(sizeof(struct history)); - new->latest_history_item = 0; - new->earliest_history_item = 0; - new->max_entries = max_entries; - new->cur_entries = 0; - return new; -} - -void del_history(struct history *hs) { - free_block(hs); - for (struct history_entry *he = hs->latest_history_item; he; he = he->prev) { - free_block(he); - free_block(he->contents); - } -} - -//return value and max_length don't include null terminator -uint32_t ask_user_line_sz_with_history(char *sz, uint32_t max_length, struct history *hs) { - char log_buf[2]; - log_buf[1] = '\0'; - struct history_entry *cur_he = 0; - - uint32_t i; - for (i = 0; i != max_length; ++i) { - char key; - replace: - key = get_key_char(); - if (!key) - goto replace; - if (key == (char)_KEY_UP) { - struct history_entry *new_cur_he = cur_he ? cur_he->prev : hs->latest_history_item; - if (new_cur_he) { - cur_he = new_cur_he; - for (uint32_t j = 0; j < i; ++j) - _log_string("\b"); - i = strcpy(sz, cur_he->contents); - _log_string(sz); - } - goto replace; - } - if (key == (char)_KEY_DOWN) { - cur_he = cur_he ? cur_he->next : 0; - for (uint32_t j = 0; j < i; ++j) - _log_string("\b"); - if (cur_he) { - i = strcpy(sz, cur_he->contents); - _log_string(sz); - } - else - i = 0; - goto replace; - } - if (key & 0x80) - goto replace;//TODO - if (key == '\b') { - if (i) { - --i; - _log_string("\b"); - } - goto replace; - } - - log_buf[0] = key; - _log_string(log_buf); - - if (key == '\n') - break; - sz[i] = key; - } - - sz[i] = '\0'; - - struct history_entry *new_he = get_block(sizeof(struct history_entry)); - new_he->contents = strdup(sz); - - new_he->next = 0; - if (hs->latest_history_item) { - new_he->prev = hs->latest_history_item; - hs->latest_history_item->next = new_he; - } - else - new_he->prev = 0; - hs->latest_history_item = new_he; - if (!hs->earliest_history_item) - hs->earliest_history_item = new_he; - if (hs->max_entries == hs->cur_entries) { - free_block(hs->earliest_history_item); - free_block(hs->earliest_history_item->contents); - hs->earliest_history_item->next->prev = 0; - hs->earliest_history_item = hs->earliest_history_item->next; - } - else - ++(hs->cur_entries); - - for (struct history_entry *check_he = hs->latest_history_item->prev; check_he; check_he = check_he->prev) { - if (blockequ(check_he->contents, sz, i + 1)) { - check_he->next->prev = check_he->prev; - if (check_he->prev) - check_he->prev->next = check_he->next; - else - hs->earliest_history_item = check_he->next; - free_block(check_he); - free_block(check_he->contents); - } - } - - return i; -} \ No newline at end of file diff --git a/src/user/libfont/bdf.c b/src/user/libfont/bdf.c new file mode 100644 index 0000000..2c19a15 --- /dev/null +++ b/src/user/libfont/bdf.c @@ -0,0 +1,99 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +#define LINE_BUF_SIZE 1000 +char line_buf[LINE_BUF_SIZE]; + +static inline uint8_t hex_to_n(char ch) { + return ch - (ch >= 'A' ? 'A' - 10 : '0'); +} + +//very minimal implementation +bool try_load_bdf(const char *path, struct font_info *into) { + struct file *f = open_file(path); + if (!f) + PANIC("Can't open font file sent by get_font."); + + read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1); + if (!strequ(line_buf, "STARTFONT 2.1")) { + close_file(f); + return false; + } + + for (uint16_t i = 0; i < 256; ++i) + into->bitmaps[i] = 0; + into->space_height = -1; + into->space_width = -1; + into->char_height = -1; + into->char_width = -1; + + uint32_t current = 0; + + while (read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1)) { + if (blockequ(line_buf, "FONTBOUNDINGBOX ", 16)) { + uint32_t n; + uint32_t l = try_swtou(line_buf + 16, &n); + if (!l) + goto bad_format; + into->space_width = n; + into->char_width = n; + l = try_swtou(line_buf + 16 + l, &n); + if (!l) + goto bad_format; + into->space_height = n; + into->char_height = n; + } + else if (blockequ(line_buf, "ENCODING ", 9)) { + if (!try_swtou(line_buf + 9, ¤t)) + goto bad_format; + } + else if (strequ(line_buf, "BITMAP")) { + if (current >= 256) + continue; + bool *bm = get_block(into->char_height * into->char_width); + if (!bm) + PANIC("could not allocate memory for font character bitmap"); + into->bitmaps[current] = bm; + + for (uint32_t y = 0; y < into->char_height; ++y) { + read_line_from_file(f, line_buf, LINE_BUF_SIZE - 1); + for (uint32_t x = 0; x < into->char_width; ++x) + bm[y * into->char_width + x] = (hex_to_n(line_buf[x / 4]) >> (3 - x % 4)) & 1; + } + } + } + + close_file(f); + f = 0; + + if ((into->char_height == -1) || + (into->char_width == -1) || + (into->space_height == -1) || + (into->space_width == -1)) + goto bad_format; + + if (!into->bitmaps[0]) { + const uint32_t bytes = (into->char_height * into->char_width - 1) / 8 + 1; + into->bitmaps[0] = get_block(bytes); + for (uint32_t i = 0; i < bytes; ++i) + into->bitmaps[0][i] = 0b01011010; + } + + return true; + +bad_format: + if (f) + close_file(f); + for (uint16_t i = 0; i < 256; ++i) + if (into->bitmaps[i]) + free_block(into->bitmaps[i]); + return false; +} \ No newline at end of file diff --git a/src/user/libfont/bdf.h b/src/user/libfont/bdf.h new file mode 100644 index 0000000..4ed4189 --- /dev/null +++ b/src/user/libfont/bdf.h @@ -0,0 +1,8 @@ +#ifndef LIBFONT_BDF_H +#define LIBFONT_BDF_H + +#include + +bool try_load_bdf(const char *path, struct font_info *into); + +#endif \ No newline at end of file diff --git a/src/user/libfont/filist.c b/src/user/libfont/filist.c new file mode 100644 index 0000000..ae24429 --- /dev/null +++ b/src/user/libfont/filist.c @@ -0,0 +1,33 @@ +#include +#include +#include + +struct dict_entry { + char *name; + struct font_info *fi; + struct dict_entry *prev; +} *last_entry = 0; + +__attribute__ ((pure)) +struct font_info *find_entry(const char *name) { + for (struct dict_entry *i = last_entry; i; i = i->prev) + if (strequ(i->name, name)) + return i->fi; + return 0; +} + +struct font_info *new_entry(const char *name) { + struct dict_entry *const nde = get_block(sizeof(struct dict_entry)); + nde->name = strdup(name); + nde->fi = get_block(sizeof(struct font_info)); + nde->prev = last_entry; + last_entry = nde; + return nde->fi; +} + +void del_last() {//only called when last_entry isn't 0 + free_block(last_entry->name); + free_block(last_entry->fi); + free_block(last_entry); + last_entry = last_entry->prev; +} \ No newline at end of file diff --git a/src/user/libfont/filist.h b/src/user/libfont/filist.h new file mode 100644 index 0000000..c78c640 --- /dev/null +++ b/src/user/libfont/filist.h @@ -0,0 +1,8 @@ +#ifndef LIBFONT_FILIST_H +#define LIBFONT_FILIST_H + +struct font_info *find_entry(const char *name) __attribute__ ((pure)); +struct font_info *new_entry(const char *name); +void del_last(); + +#endif \ No newline at end of file diff --git a/src/user/libfont/fonts.c b/src/user/libfont/fonts.c new file mode 100644 index 0000000..1692992 --- /dev/null +++ b/src/user/libfont/fonts.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include + +#include "filist.h" +#include "bdf.h" + +#define FONT_PATH "fonts/" +#define FONT_PATH_L 6 + +struct font_loader_t { + const char *ext; + bool (*func)(const char *, struct font_info *); +} font_loaders[] = { + { .ext = ".bdf", + .func = try_load_bdf + }, + { .ext = "" + } +}; + +struct font_info *get_font(const char *name) { + struct font_info *font = find_entry(name); + if (font) + return font; + font = new_entry(name); + if (!font) + return 0;//out of memory? + + const uint32_t name_len = strlen(name); + for (struct font_loader_t *i = font_loaders; i->ext[0]; ++i) { + char *buf = get_block(FONT_PATH_L + name_len + strlen(i->ext) + 1); + blockcpy(buf, FONT_PATH, FONT_PATH_L); + blockcpy(buf + FONT_PATH_L, name, name_len); + strcpy(buf + FONT_PATH_L + name_len, i->ext); + struct file *f = open_file(buf); + if (!f) { + free_block(buf); + continue; + } + syslogf("[libfont] Loading %s%s...", name, i->ext); + if (i->func(buf, font)) { + close_file(f); + free_block(buf); + syslogf("[libfont] Loaded %s%s.", name, i->ext); + return font; + } + close_file(f); + free_block(buf); + syslogf("[libfont] Failed to load %s%s.", name, i->ext); + } + del_last(); + return 0; +} + +void put_char(const struct font_info *font, char ch, uint8_t *pb_ptr, uint32_t pb_pitch, uint8_t bg, uint8_t fg) { +//char *const msg = format("put_char(font = 0x%x, ch = '%c', pb_ptr = 0x%x, pb_pitch = %u, bg = 0x%2x, fg = 0x%2x);", font, ch, pb_ptr, pb_pitch, bg, fg); +//_system_log(msg); +//free_block(msg); + const bool *const bitmap = font->bitmaps[(uint8_t)ch] ? font->bitmaps[(uint8_t)ch] : font->bitmaps[0]; + for (uint32_t y = 0; y < font->char_height; ++y) + for (uint32_t x = 0; x < font->char_width; ++x) + pb_ptr[y * pb_pitch + x] = bitmap[y * font->char_width + x] ? fg : bg; +} \ No newline at end of file diff --git a/src/user/manual/manual.c b/src/user/manual/manual.c deleted file mode 100644 index d1af406..0000000 --- a/src/user/manual/manual.c +++ /dev/null @@ -1,303 +0,0 @@ -#include -#include -#include -#include -#include - -#define ERROR_COLOR _COLOR_BG_LGRAY | _COLOR_FG_RED -#define UI_COLOR _COLOR_BG_LGRAY | _COLOR_FG_BLACK -#define DEFAULT_TEXT_COLOR _COLOR_BG_BLACK | _COLOR_FG_WHITE - -#define MAN_ROOT "man/" -#define MRL 4 -#define MAN_EXT "man" - -#define MAX_PATH_LEN 255 - -#define SP80 " " -#define SP79 " " -#define SP69 " " -#define SP10 " " - -struct file *cur_file = 0; - -char *name_backup = 0; - -uint32_t *line_offsets = 0; -uint32_t n_lines; - -struct link { - uint32_t line; - uint8_t col; - uint8_t len; - char *lto; -}; - -struct link *link_table_start = 0; -struct link *link_table_end; - -struct link *cur_link = 0; - -uint32_t line_on; - -#define DATA_BUF_SIZE 2000 - -void print_page() { - uint8_t buf[DATA_BUF_SIZE];//1840 + up to 160 color codes - seek_file_to(cur_file, line_offsets[line_on]); - uint8_t *bufp = buf + DATA_BUF_SIZE; - uint8_t *bufend; - uint8_t row = 1, col = 0; - - _set_color(DEFAULT_TEXT_COLOR); - while (row != 24) { - if (bufp == buf + DATA_BUF_SIZE) { - bufp = buf; - uint16_t bl = read_from_file(cur_file, DATA_BUF_SIZE, buf); - bufend = bl == DATA_BUF_SIZE ? 0 : buf + bl; - } - if (bufp == bufend) { - uint32_t *i = buf; - uint16_t l = 80 - col + (23 - row) * 80; - uint32_t *e = i + l / 4 + 1; - while (i != e) - *(i++) = 0x20202020; - buf[l] = '\0'; - _print_at(row, col, buf); - break; - } - if (*bufp & 0x80) - _set_color(*bufp & 0x7f); - else { - char bufpb[2] = {*bufp, '\0'}; - _print_at(row, col, bufpb); - if (++col == 80) { - col = 0; - ++row; - } - } - ++bufp; - } - - if (cur_link) - for (uint8_t c = cur_link->col; c < cur_link->col + cur_link->len; ++c) - _swap_color(cur_link->line - line_on + 1, c); -} - -void scroll_to(uint32_t n) { - if (n > n_lines - 23) - n = n_lines - 23; - - if (cur_link && ((cur_link->line < n) || (cur_link->line >= n + 23))) - cur_link = 0; - - line_on = n; - print_page(); - - char b[16] = "Line "; - itosz(line_on, b + 5); - - _set_color(UI_COLOR); - _print_at(24, 0, SP69); - _print_at(24, 0, b); -} - -void scroll_link() { - if (cur_link->line < line_on) - scroll_to(cur_link->line); - else if (cur_link->line >= line_on + 23) - scroll_to(cur_link->line - 22); - else - print_page(); -} - -void load_file(const char *name) { - static char cur_page[MAX_PATH_LEN + 1] = MAN_ROOT; - uint32_t name_len = strcpy(cur_page + MRL, name); - strcpy(cur_page + MRL + name_len, "." MAN_EXT); - - struct file *new_file = open_file(cur_page); - if (!new_file) { - _set_color(ERROR_COLOR); - _print_at(24, 0, SP79); - _print_at(24, 0, "Could not open file."); - return; - } - - if (name_backup) - free_block(name_backup); - name_backup = strdup(name); - - if (cur_file) - close_file(cur_file); - cur_file = new_file; - - uint32_t tlen; - read_from_file(cur_file, 4, &tlen); - char title[81]; - read_from_file(cur_file, tlen + 1, title); - - _set_color(UI_COLOR); - _print_at(0, 0, SP80); - _print_at(0, 0, title); - - if (link_table_start) { - for (struct link *l = link_table_start; l != link_table_end; ++l) - free_block(l->lto); - free_block(link_table_start); - } - - uint32_t linktc; - read_from_file(cur_file, 4, &linktc); - if (linktc) { - link_table_start = get_block(sizeof(struct link) * linktc); - link_table_end = link_table_start + linktc; - read_from_file(cur_file, 4, &linktc);//dummy - - for (struct link *l = link_table_start; l != link_table_end; ++l) { - read_from_file(cur_file, 4, &l->line); - read_from_file(cur_file, 1, &l->col); - read_from_file(cur_file, 1, &l->len); - uint32_t lto_l; - read_from_file(cur_file, 4, <o_l); - l->lto = get_block(lto_l + 1); - read_from_file(cur_file, lto_l + 1, l->lto); - } - } - else { - link_table_start = 0; - read_from_file(cur_file, 4, &linktc);//dummy - } - - cur_link = 0; - - if (line_offsets) - free_block(line_offsets); - - read_from_file(cur_file, 4, &n_lines); - line_offsets = get_block(n_lines * 4); - read_from_file(cur_file, n_lines * 4, line_offsets); - - char b[11]; - itosz(n_lines, b); - - _set_color(UI_COLOR); - _print_at(24, 69, SP10); - _print_at(24, 69, b); - - scroll_to(0); -} - -struct stack_entry { - struct stack_entry *down; - char *name; - uint32_t line; -}; - -struct stack_entry *stack_top = 0; - -void push() { - struct stack_entry *new_entry = get_block(sizeof(struct stack_entry)); - new_entry->down = stack_top; - new_entry->name = strdup(name_backup); - new_entry->line = line_on; - stack_top = new_entry; -} - -void pop() { - if (stack_top) { - load_file(stack_top->name); - scroll_to(stack_top->line); - free_block(stack_top->name); - free_block(stack_top); - stack_top = stack_top->down; - } -} - -void main() { - _set_color(UI_COLOR); - _print_at(24, 79, " "); - - load_file("index"); - - while (true) { - switch (_get_key()) { - case 0: - default: - _yield_task(); - break; - case _KEY_UP: - if (n_lines <= 23) - break; - if (line_on) - scroll_to(line_on - 1); - break; - case _KEY_DOWN: - if (n_lines <= 23) - break; - if (line_on < n_lines - 23) - scroll_to(line_on + 1); - break; - case _KEY_PUP: - if (n_lines <= 23) - break; - scroll_to(line_on <= 22 ? 0 : line_on - 22); - break; - case _KEY_PDOWN: - if (n_lines <= 23) - break; - scroll_to(line_on + 22); - break; - case _KEY_LEFT: - if (cur_link == link_table_start) - break; - if (cur_link) { - --cur_link; - scroll_link(); - } - else if (link_table_start) { - struct link *l = link_table_end; - while (l != link_table_start) { - --l; - if (l->line <= line_on + 22) - break; - } - cur_link = l; - scroll_link(); - } - break; - case _KEY_RIGHT: - if (cur_link == link_table_end - 1) - break; - if (cur_link) { - ++cur_link; - scroll_link(); - } - else if (link_table_start) { - struct link *l = link_table_start; - while (l != link_table_end) { - if (l->line >= line_on) - break; - ++l; - } - cur_link = l; - scroll_link(); - } - break; - case ' ': - case '\n': - case _KEY_NENTER: - if (cur_link) { - push(); - load_file(cur_link->lto); - } - break; - case _KEY_ESC: - if (stack_top) - pop(); - break; - case 'q': - return; - } - } -} \ No newline at end of file diff --git a/src/user/meminfo/meminfo.c b/src/user/meminfo/meminfo.c index dd1d371..124a136 100644 --- a/src/user/meminfo/meminfo.c +++ b/src/user/meminfo/meminfo.c @@ -1,19 +1,30 @@ -#include -#include -#include - -void main() { - char nbuf[11]; +#include - tell_user_sz("Kernel dynamic memory remaining: "); - - itosz(_kernel_dynamic_area_left() * 4, nbuf); - tell_user_sz(nbuf); - tell_user_sz("k\n"); +#include - tell_user_sz("Userspace memory remaining: "); +static const struct key_packet meminfo_quits[] = { + { .key_id = KEY_ESCAPE, .modifiers = NO_MODS }, + { .key_id = KEY_F5, .modifiers = NO_MODS }, + { .key_id = 0 } +}; - itosz(_total_userspace_left() * 4, nbuf); - tell_user_sz(nbuf); - tell_user_sz("k\n"); +void main() { + struct popup p; +redo: + info_popupf(&p, + "kernel memory free: %uk\n" + "userspace memory free: %uk / %uk\n" + "Escape to quit, F5 to refresh.", + 0x10, 0x08, + _kernel_dynamic_area_left() * 4, + _total_userspace_left() * 4, + _total_userspace_size() * 4 + ); + //hacky, i should really make info_popup take an arg + p.quit_binds = meminfo_quits; + make_modal(&p); + if (p.quit_as.key_id == KEY_F5) + //i should make popups have changable text + //(make a new pixbuf but reuse the window) + goto redo; } \ No newline at end of file diff --git a/src/user/popups/info.c b/src/user/popups/info.c new file mode 100644 index 0000000..81a09e9 --- /dev/null +++ b/src/user/popups/info.c @@ -0,0 +1,99 @@ +#include + +#include + +#include +#include + +#include +#include + +#define BORDER_SIZE 2 +//includes border +#define PADDING 8 +#define FONT "berry" + +#define BORDER_COLOR 0x10 +#define BG_COLOR 0x07 +#define FG_COlOR 0x10 + +static const struct font_info *info_font = 0; + +static const struct key_packet info_quits[] = { + { .key_id = KEY_ESCAPE, .modifiers = NO_MODS }, + { .key_id = 0 } +}; + +void info_popup(struct popup *into, const char *msg, uint8_t fg, uint8_t bg) { + if (!info_font) + info_font = get_font(FONT); + + uint32_t w = 0, h = 1, lw = 0; + for (const char *i = msg; *i; ++i) + if (*i == '\n') { + ++h; + if (lw > w) + w = lw; + lw = 0; + } + else + ++lw; + if (lw > w) + w = lw; + + into->has_quit = false; + into->quit_binds = (struct key_packet *)info_quits; + into->free_quit_binds = false; + + const uint32_t pitch = info_font->space_width * w + 2 * PADDING; + const uint32_t height = info_font->space_height * h + 2 * PADDING; + + uint8_t *const pixbuf = get_block(pitch * height); + + for (uint32_t i = 0; i < pitch * BORDER_SIZE; ++i) + pixbuf[i] = BORDER_COLOR; + for (uint32_t y = BORDER_SIZE; y < height - BORDER_SIZE; ++y) { + for (uint32_t x = 0; x < BORDER_SIZE; ++x) + pixbuf[y * pitch + x] = BORDER_COLOR; + for (uint32_t x = pitch - BORDER_SIZE; x < pitch; ++x) + pixbuf[y * pitch + x] = BORDER_COLOR; + } + for (uint32_t i = 0; i < pitch * BORDER_SIZE; ++i) + pixbuf[(height - BORDER_SIZE) * pitch + i] = BORDER_COLOR; + + for (uint32_t y = BORDER_SIZE; y < height - BORDER_SIZE; ++y) + for (uint32_t x = BORDER_SIZE; x < pitch - BORDER_SIZE; ++x) + pixbuf[y * pitch + x] = BG_COLOR; + + uint32_t my = 0; + uint32_t mx = 0; + --msg; + while (*++msg) { + if (*msg == '\n') { + ++my; + mx = 0; + } + else { + //syslogf("calling put_char(0x%x, '%c', pixbuf + %u, %u, 0x%2x, 0x%2x)", info_font, *msg, + // (my * info_font->space_height + PADDING) * pitch + mx * info_font->space_width + PADDING, + // pitch, BG_COLOR, FG_COlOR); + put_char(info_font, *msg, pixbuf + (my * info_font->space_height + PADDING) * pitch + mx++ * info_font->space_width + PADDING, pitch, BG_COLOR, FG_COlOR); + } + } + + into->pixbuf = pixbuf; + into->handle = _new_window(pitch, height, pixbuf); +} + +void info_popupf_v(struct popup *into, const char *text, uint8_t fg, uint8_t bg, va_list args) { + char *const msg = format_v(text, args); + info_popup(into, msg, fg, bg); + free_block(msg); +} + +void info_popupf(struct popup *into, const char *text, uint8_t fg, uint8_t bg, ...) { + va_list args; + va_start(args, bg); + info_popupf_v(into, text, fg, bg, args); + va_end(args); +} \ No newline at end of file diff --git a/src/user/popups/popup.c b/src/user/popups/popup.c new file mode 100644 index 0000000..d214f81 --- /dev/null +++ b/src/user/popups/popup.c @@ -0,0 +1,45 @@ +#include + +#include +#include + +#include + +void handle_actions(struct popup *p) { + if (p->has_quit) + return; + struct window_action a; + while (1) { + _get_win_action(p->handle, &a); + if (a.action_type == NOT_READY) + return; + if ((a.action_type == KEY_DOWN)) { + //syslogf("got key 0x%2x, 0x%3x", a.as_key.key_id, a.as_key.modifiers); + for (const struct key_packet *kp = p->quit_binds; kp->key_id; ++kp) { + //syslogf("checking against 0x%2x, 0x%3x", kp->key_id, kp->modifiers); + if ((a.as_key.key_id == kp->key_id) && (a.as_key.modifiers == kp->modifiers)) { + p->has_quit = true; + p->quit_as = a.as_key; + return; + } + } + } + } +} + +void delete_popup(struct popup *p) { + _delete_window(p->handle); + free_block(p->pixbuf); + if (p->free_quit_binds) + free_block(p->quit_binds); +} + +void make_modal(struct popup *p) { + handle_actions(p); + while (!p->has_quit) { + _wait_for_action(); + _yield_task(); + handle_actions(p); + } + delete_popup(p); +} \ No newline at end of file diff --git a/src/user/runtimes/c/elf.ld b/src/user/runtimes/c/elf.ld index f321be2..3e9a034 100644 --- a/src/user/runtimes/c/elf.ld +++ b/src/user/runtimes/c/elf.ld @@ -11,6 +11,7 @@ SECTIONS { .__pcrt_before_main : { __pcrt_before_main_start = .; *(.__pcrt_before_main) + *(.init_array) __pcrt_before_main_end = .; } diff --git a/src/user/runtimes/c/entry.asm b/src/user/runtimes/c/entry.asm deleted file mode 100644 index bba8060..0000000 --- a/src/user/runtimes/c/entry.asm +++ /dev/null @@ -1,42 +0,0 @@ -bits 32 - -global __pcrt_entry -global __pcrt_quit - -extern main -extern __pcrt_before_main_start -extern __pcrt_before_main_end -extern __pcrt_before_quit_start -extern __pcrt_before_quit_end - -section .text -__pcrt_entry: - mov esp, stack - push edx - - mov ebx, __pcrt_before_main_start -.before_main_loop: - cmp ebx, __pcrt_before_main_end - je .call_main - call dword [ebx] - add ebx, 4 - jmp .before_main_loop - -.call_main: - call main - -__pcrt_quit: - mov ebx, __pcrt_before_quit_start -.before_quit_loop: - cmp ebx, __pcrt_before_quit_end - je .end_task - call dword [ebx] - add ebx, 4 - jmp .before_quit_loop - -.end_task: - int 0x38 - -section .stack nobits alloc noexec write align=16 -resb 4096 -stack: \ No newline at end of file diff --git a/src/user/runtimes/c/pcrt.asm b/src/user/runtimes/c/pcrt.asm new file mode 100644 index 0000000..85c898c --- /dev/null +++ b/src/user/runtimes/c/pcrt.asm @@ -0,0 +1,45 @@ +bits 32 + +global __pcrt_entry +global __pcrt_quit +global calling_task +global stdio_task + +extern main +extern __pcrt_before_main_start +extern __pcrt_before_main_end +extern __pcrt_before_quit_start +extern __pcrt_before_quit_end + +section .text +__pcrt_entry: + mov dword [calling_task], esi + mov dword [stdio_task], edi + push edx + + mov ebx, __pcrt_before_main_start +.before_main_loop: + cmp ebx, __pcrt_before_main_end + je .call_main + call dword [ebx] + add ebx, 4 + jmp .before_main_loop + +.call_main: + call main + +__pcrt_quit: + mov ebx, __pcrt_before_quit_start +.before_quit_loop: + cmp ebx, __pcrt_before_quit_end + je .end_task + call dword [ebx] + add ebx, 4 + jmp .before_quit_loop + +.end_task: + int 0x38 + +section .bss +calling_task resd 1 +stdio_task resd 1 \ No newline at end of file diff --git a/src/user/terminal/readline.c b/src/user/terminal/readline.c new file mode 100644 index 0000000..37ef54b --- /dev/null +++ b/src/user/terminal/readline.c @@ -0,0 +1,104 @@ +#include + +#include +#include +#include + +#include + +#include + +//returns length of string without null terminator +//max_length doesn't include null terminator +uint32_t read_line(char *sz, uint32_t max_length, const char *prompt) { + uint32_t i = 0; + uint32_t l = 0; + + term_add_sz_no_ww(prompt); + paint_term(); + + const _window_handle_t handle = active_term->window; + struct window_action action; + while (1) { + _get_win_action(handle, &action); + switch (action.action_type) { + case NOT_READY: + _wait_for_action(); + _yield_task(); + continue; + case KEY_DOWN: + //;char *const debug_msg = format("got key 0x%2x, 0x%3x", action.as_key.key_id, action.as_key.modifiers); + // _system_log(debug_msg); + // free_block(debug_msg); + switch (action.as_key.key_id) { + case KEY_DELETE: + if (i != l) { + cursor_right(); + ++i; + } + case KEY_BSPACE: + if (!i) + continue; + --l; + --i; + for (uint8_t j = i; j < l; ++j) + sz[j] = sz[j + 1]; + sz[l] = '\0'; + cursor_left(); + uint32_t cursor_backup_x = active_term->cursor_x; + uint32_t cursor_backup_y = active_term->cursor_y; + term_add_sz_no_ww(sz + i); + term_add_char(' '); + move_cursor(cursor_backup_y, cursor_backup_x); + paint_term(); + continue; + case KEY_ENTER: + term_newline(); + paint_term(); + sz[l] = '\0'; + return l; + case KEY_HOME: + case KEY_UP_ARROW: + for (; i; --i) + cursor_left(); + paint_term(); + continue; + case KEY_END: + case KEY_DOWN_ARROW: + for (; i != l; ++i) + cursor_right(); + paint_term(); + continue; + case KEY_LEFT_ARROW: + if (i) { + cursor_left(); + paint_term(); + --i; + } + continue; + case KEY_RIGHT_ARROW: + if (i != l) { + cursor_right(); + paint_term(); + ++i; + } + continue; + default: + if (i == max_length) + continue; + char ch = key_to_char(action.as_key); + if (ch) { + term_add_char(ch); + paint_term(); + sz[i] = ch; + if (i == l) + ++l; + ++i; + } + continue; + } + default: + continue; + } + } +} \ No newline at end of file diff --git a/src/user/terminal/terminal.c b/src/user/terminal/terminal.c new file mode 100644 index 0000000..7961fd5 --- /dev/null +++ b/src/user/terminal/terminal.c @@ -0,0 +1,284 @@ +#include + +#include + +#include +#include + +struct term_list_entry { + struct terminal term; + struct term_list_entry *next; + struct term_list_entry *prev; +}; + +struct term_list_entry *last_term = 0; +struct terminal *active_term = 0; + +struct terminal *make_term(struct font_info *font, uint32_t cols, uint32_t rows) { + if (!font) + return 0; + + struct term_list_entry *next_entry = get_block(sizeof(struct term_list_entry)); + if (!next_entry) + return 0; + + char *const cb = get_block(cols * rows); + + if (!cb) { + free_block(next_entry); + return 0; + } + + const uint32_t w = cols * font->space_width; + const uint32_t h = rows * font->space_height; + + uint8_t *const pb = get_block(w * h); + if (!pb) { + free_block(next_entry); + free_block(cb); + return 0; + } + + _window_handle_t win = _new_window(w, h, pb); + if (!win) { + free_block(next_entry); + free_block(cb); + free_block(pb); + return 0; + } + + for (char *i = cb; i < cb + cols * rows; ++i) + *i = ' '; + for (uint8_t *i = pb; i < pb + w * h; ++i) + *i = 0x10; + + next_entry->term.window = win; + next_entry->term.pixbuf = pb; + next_entry->term.window_width = w; + next_entry->term.window_height = h; + + next_entry->term.font = font; + + next_entry->term.cols = cols; + next_entry->term.rows = rows; + next_entry->term.charbuf = cb; + + next_entry->term.cursor_y = 0; + next_entry->term.cursor_x = 0; + + next_entry->term.fg = 0x0f; + next_entry->term.bg = 0x10; + + next_entry->prev = last_term; + next_entry->next = 0; + + if (last_term) + last_term->next = next_entry; + last_term = next_entry; + + return (struct terminal *)next_entry; +} + +void del_term(struct terminal *term) { + _delete_window(term->window); + free_block(term->pixbuf); + free_block(term->charbuf); + + free_block(term);//coincides with the term_list_entry + if (active_term == term) + active_term = 0; + + for (struct term_list_entry *i = last_term; i; i = i->prev) + if (i == (struct term_list_entry *)term) { + if (i->prev) + i->prev->next = i->next; + if (i->next) + i->next->prev = i->prev; + if (i == last_term) + last_term = i->prev; + return; + } +} + +static void draw_char(uint32_t y, uint32_t x, bool inverted) { + put_char(active_term->font, active_term->charbuf[y * active_term->cols + x], active_term->pixbuf + (y * active_term->cols * active_term->font->space_height + x) * active_term->font->space_width, active_term->window_width, inverted ? active_term->fg : active_term->bg, inverted ? active_term->bg : active_term->fg); +} + +static void draw_cursor() { + draw_char(active_term->cursor_y, active_term->cursor_x, true); +} + +void paint_term() { + _paint_window(active_term->window); +} + +void move_cursor(uint32_t new_y, uint32_t new_x) { + draw_char(active_term->cursor_y, active_term->cursor_x, false); + active_term->cursor_y = new_y; + active_term->cursor_x = new_x; + draw_cursor(); +} + +static void redraw_term() { + for (uint32_t y = 0; y < active_term->rows; ++y) + for (uint32_t x = 0; x < active_term->cols; ++x) + draw_char(y, x, false); + draw_cursor(); +} + +void set_color(uint8_t fg, uint8_t bg) { + active_term->fg = fg; + active_term->bg = bg; + redraw_term(); +} + +void clear_term() { + for (char *i = active_term->charbuf, *const e = i + active_term->cols * active_term->rows; i != e; ++i) + *i = ' '; + for (uint8_t *i = active_term->pixbuf, *const e = i + active_term->window_width * active_term->window_height; i != e; ++i) + *i = active_term->bg; + move_cursor(0, 0); +} + +void cursor_up() { + draw_char(active_term->cursor_y, active_term->cursor_x, false); + if (active_term->cursor_y) + --active_term->cursor_y; + else + //eventually, maybe scroll back through a longer terminal buffer + active_term->cursor_x = 0; + draw_cursor(); +} + +void cursor_left() { + draw_char(active_term->cursor_y, active_term->cursor_x, false); + if (active_term->cursor_x) { + --active_term->cursor_x; + draw_cursor(); + } + else { + active_term->cursor_x = active_term->cols - 1; + cursor_up(); + } +} + +void cursor_down() { + draw_char(active_term->cursor_y, active_term->cursor_x, false); + + const uint32_t rows = active_term->rows; + + if (++active_term->cursor_y == rows) { + --active_term->cursor_y; + + char *const cb = active_term->charbuf; + uint8_t *const pb = active_term->pixbuf; + const uint32_t cols = active_term->cols; + const uint32_t fw = active_term->font->space_width; + const uint32_t fh = active_term->font->space_height; + + char *to; + for (to = cb; to < cb + (rows - 1) * cols; ++to) + *to = *(to + cols); + for (; to < cb + rows * cols; ++to) + *to = ' '; + uint8_t *pto; + for (pto = pb; pto < pb + cols * fw * (rows - 1) * fh; ++pto) + *pto = *(pto + cols * fw * fh); + for (; pto < pb + cols * fw * rows * fh; ++pto) + *pto = active_term->bg; + } + + draw_cursor(); +} + +void cursor_right() { + draw_char(active_term->cursor_y, active_term->cursor_x, false); + + if (++active_term->cursor_x == active_term->cols) + term_newline(); + else + draw_cursor(); +} + +void term_newline() { + draw_char(active_term->cursor_y, active_term->cursor_x, false); + active_term->cursor_x = 0; + cursor_down(); +} + +void term_add_char(char ch) { + if (ch == '\n') { + term_newline(); + return; + } +//char *const debug_msg = format("charbuf[%u] = '%c'", active_term->cursor_y * active_term->cols + active_term->cursor_x, ch); +//_system_log(debug_msg); +//free_block(debug_msg); + active_term->charbuf[active_term->cursor_y * active_term->cols + active_term->cursor_x] = ch; + cursor_right(); +} + +void term_add_sz_no_ww(const char *sz) { + while (*sz) + term_add_char(*(sz++)); +} + +#define MIN_TAB 3 +#define TAB_STEP 4 + +void term_add_sz(const char *sz) { + //TODO: special hyphen handling + const char *word = sz; + while (1) + if (!*sz || (*sz == ' ') || (*sz == '\n') || (*sz == '\t')) { + const uint32_t len = sz - word; + if ((active_term->cursor_x + len > active_term->cols) && (len <= active_term->cols) && active_term->cols) + term_newline(); + for (const char *i = word; i < sz; ++i) + term_add_char(*i); + while ((*sz == ' ') || (*sz == '\n') || (*sz == '\t')) { + if (*sz == '\n') + term_newline(); + else if (*sz == '\t') { + for (uint8_t i = 0; i < MIN_TAB; ++i) + cursor_right(); + while (active_term->cursor_x % TAB_STEP) + cursor_right(); + } + ++sz; + } + if (!*sz) + return; + if (active_term->cursor_x) + term_add_char(' '); + word = sz; + } + else + ++sz; +} + +void term_addf_no_ww_v(const char *fmt, va_list args) { + char *const msg = format_v(fmt, args); + term_add_sz_no_ww(msg); + free_block(msg); +} + +void term_addf_no_ww(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + term_addf_no_ww_v(fmt, args); + va_end(args); +} + +void term_addf_v(const char *fmt, va_list args) { + char *const msg = format_v(fmt, args); + term_add_sz(msg); + free_block(msg); +} + +void term_addf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + term_addf_v(fmt, args); + va_end(args); +} \ No newline at end of file -- cgit v1.2.3