From 47513bd32c256c4f35e3a8ced7d9fd7e15903530 Mon Sep 17 00:00:00 2001 From: Benji Dial Date: Tue, 16 Feb 2021 20:38:53 -0500 Subject: terminal application with ipc, shift+pause state dumper, hello world for terminal, meminfo popup program --- src/kernel/dump.c | 187 ++++++++++++++++++ src/kernel/elf-link.ld | 2 + src/kernel/elf.c | 9 +- src/kernel/idt.c | 50 +++-- src/kernel/isrs.asm | 12 ++ src/kernel/kbd.c | 6 +- src/kernel/kbd.h | 8 +- src/kernel/log.c | 5 + src/kernel/log.h | 1 + src/kernel/paging.c | 5 +- src/kernel/paging.h | 4 +- src/kernel/task.c | 101 ++++++---- src/kernel/task.h | 12 +- src/kernel/window.c | 25 ++- src/kernel/window.h | 6 +- src/user/hello/hello.asm | 28 +++ src/user/highway/cmds.c | 2 +- src/user/highway/line.c | 30 ++- src/user/highway/main.c | 23 +-- src/user/highway/vars.c | 5 +- src/user/include/knob/ipc.h | 2 +- src/user/include/libterm/command.h | 68 +++++++ src/user/include/libterm/readline.h | 10 + src/user/include/libterm/terminal.h | 35 ++++ src/user/include/pland/pcrt.h | 1 + src/user/include/pland/syscall.h | 20 +- src/user/include/popups/popup.h | 3 +- src/user/include/terminal/readline.h | 10 - src/user/include/terminal/terminal.h | 57 ------ src/user/knob/format.c | 19 +- src/user/knob/ipc.c | 12 +- src/user/knob/task.c | 16 +- src/user/libterm/readline.c | 106 ++++++++++ src/user/libterm/terminal.c | 179 +++++++++++++++++ src/user/libterm/termtask.c | 9 + src/user/popups/info.c | 1 - src/user/popups/popup.c | 2 - src/user/runtimes/c/pcrt.asm | 9 +- src/user/terminal/main.c | 373 +++++++++++++++++++++++++++++++++++ src/user/terminal/readline.c | 104 ---------- src/user/terminal/terminal.c | 284 -------------------------- 41 files changed, 1244 insertions(+), 597 deletions(-) create mode 100644 src/kernel/dump.c create mode 100644 src/user/hello/hello.asm create mode 100644 src/user/include/libterm/command.h create mode 100644 src/user/include/libterm/readline.h create mode 100644 src/user/include/libterm/terminal.h delete mode 100644 src/user/include/terminal/readline.h delete mode 100644 src/user/include/terminal/terminal.h create mode 100644 src/user/libterm/readline.c create mode 100644 src/user/libterm/terminal.c create mode 100644 src/user/libterm/termtask.c create mode 100644 src/user/terminal/main.c delete mode 100644 src/user/terminal/readline.c delete mode 100644 src/user/terminal/terminal.c (limited to 'src') diff --git a/src/kernel/dump.c b/src/kernel/dump.c new file mode 100644 index 0000000..d0c02e6 --- /dev/null +++ b/src/kernel/dump.c @@ -0,0 +1,187 @@ +#include + +#include "paging.h" +#include "task.h" +#include "log.h" + +extern const void _kernel_data_start; +extern const void _kernel_data_end; +extern const void _kernel_bss_end; + +static inline char c(uint8_t n) { + return (n > 0x20) && (n < 0x7f) ? (char)n : '.'; +} + +static uint8_t last_line[16]; +enum { + SECTION_START, + DOT_DOT_DOT, + SKIP +} last_line_mode; + +static void write_mem_line(uint32_t addr) { + const uint8_t *const at = (const uint8_t *)addr; + if (last_line_mode != SECTION_START) { + for (uint8_t i = 0; i < 16; ++i) + if (at[i] != last_line[i]) + goto diff_line; + if (last_line_mode == DOT_DOT_DOT) { + logf(LOG_DUMP, " 0x%h ...", addr); + last_line_mode = SKIP; + } + return; + } +diff_line: + logf(LOG_DUMP, + " 0x%h %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %hb %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c", addr, + at[0], at[1], at[2], at[3], at[4], at[5], at[6], at[7], + at[9], at[9], at[10], at[11], at[12], at[13], at[14], at[15], + c(at[0]), c(at[1]), c(at[2]), c(at[3]), + c(at[4]), c(at[5]), c(at[6]), c(at[7]), + c(at[8]), c(at[9]), c(at[10]), c(at[11]), + c(at[12]), c(at[13]), c(at[14]), c(at[15]) + ); + for (uint8_t i = 0; i < 16; ++i) + last_line[i] = at[1]; + last_line_mode = DOT_DOT_DOT; +} + +static void write_mem_page(uint32_t page) { + for (uint32_t i = page << 12; i < (page + 1) << 12; i += 16) + write_mem_line(i); +} + +#include "kbd.h" + +#define WAIT_TASK tasks[i].waits[t].task - tasks + 1, tasks[i].waits[t].task->name + +void dump(enum kbd_isr_result kind, const uint32_t edi, const uint32_t esi, const uint32_t ebx, const uint32_t edx, const uint32_t ecx, const uint32_t eax, const uint32_t eip, const uint32_t cs, const uint32_t eflags, const uint32_t esp, const uint32_t ss) { + uint32_t cr3; + asm volatile ( + "mov %%cr3, %0" + : "=a" (cr3)); + + logf(LOG_INFO, "Dump state..."); + + switch (kind) { + case DUMP: + logf(LOG_DUMP, "Tasks:"); + for (uint8_t t = 0; t < MAX_TASKS; ++t) + if (tasks[t].page_directory) { + logf(LOG_DUMP, " %s (0x%hb):", tasks[t].name, t + 1); + if (tasks + t == active_task) { + logf(LOG_DUMP, " *Active task*"); + logf(LOG_DUMP, " cr3: 0x%h", cr3); + logf(LOG_DUMP, " eip: 0x%h", eip); + logf(LOG_DUMP, " eax: 0x%h", eax); + logf(LOG_DUMP, " ebx: 0x%h", ebx); + logf(LOG_DUMP, " ecx: 0x%h", ecx); + logf(LOG_DUMP, " edx: 0x%h", edx); + logf(LOG_DUMP, " esi: 0x%h", esi); + logf(LOG_DUMP, " edi: 0x%h", edi); + logf(LOG_DUMP, " esp: 0x%h", esp); + logf(LOG_DUMP, " cs: 0x%hb", cs); + logf(LOG_DUMP, " ss: 0x%hb", ss); + logf(LOG_DUMP, " eflags: 0x%h", eflags); + } + else { + logf(LOG_DUMP, " Stored cr3: 0x%h", tasks[t].page_directory); + logf(LOG_DUMP, " Stored eip: 0x%h", tasks[t].ret_addr); + logf(LOG_DUMP, " Stored ebx: 0x%h", tasks[t].ebx); + logf(LOG_DUMP, " Stored ecx: 0x%h", tasks[t].ecx); + logf(LOG_DUMP, " Stored edx: 0x%h", tasks[t].edx); + logf(LOG_DUMP, " Stored esi: 0x%h", tasks[t].esi); + logf(LOG_DUMP, " Stored edi: 0x%h", tasks[t].edi); + logf(LOG_DUMP, " Stored ebp: 0x%h", tasks[t].ebp); + logf(LOG_DUMP, " Stored esp: 0x%h", tasks[t].esp); + } + logf(LOG_DUMP, " Stack size: %d kibibytes", -tasks[t].stack_bottom / 1024); + if (tasks[t].waiting) { + logf(LOG_DUMP, " Waits:"); + for (uint8_t i = 0; i < MAX_WAITS; ++i) + switch (tasks[i].waits[t].mode) { + case NONE: + continue; + case PROCESS_END: + logf(LOG_DUMP, " Waiting for task 0x%hb (%s) to end", WAIT_TASK); + continue; + case WINDOW_ACTION: + logf(LOG_DUMP, " Waiting for window action"); + continue; + case IPC_SENT: + logf(LOG_DUMP, " Waiting for IPC to be sent by 0x%hb (%s)", WAIT_TASK); + continue; + case IPC_SENT_ANY: + logf(LOG_DUMP, " Waiting for IPC to be sent by anyone"); + continue; + case IPC_READ: + logf(LOG_DUMP, " Waiting for IPC to be read by 0x%hb (%s)", WAIT_TASK); + continue; + default: + logf(LOG_DUMP, " Other (corrupted?)"); + continue; + } + } + else + logf(LOG_DUMP, " Not waiting."); + } + break; + + case SHIFT_DUMP: + + logf(LOG_DUMP, "Current task: 0x%hb (%s)", active_task - tasks + 1, active_task->name); + logf(LOG_DUMP, "Registers:"); + logf(LOG_DUMP, " cr3: 0x%h", cr3); + logf(LOG_DUMP, " eip: 0x%h", eip); + logf(LOG_DUMP, " esp: 0x%h", esp); + logf(LOG_DUMP, " eax: 0x%h", eax); + logf(LOG_DUMP, " ebx: 0x%h", ebx); + logf(LOG_DUMP, " ecx: 0x%h", ecx); + logf(LOG_DUMP, " edx: 0x%h", edx); + logf(LOG_DUMP, " esi: 0x%h", esi); + logf(LOG_DUMP, " edi: 0x%h", edi); + logf(LOG_DUMP, " eflags: 0x%h", eflags); + logf(LOG_DUMP, " cs: 0x%hb", cs); + logf(LOG_DUMP, " ss: 0x%hb", ss); + + logf(LOG_DUMP, "Kernel data section:"); + last_line_mode = SECTION_START; + for (uint32_t i = (uint32_t)&_kernel_data_start & ~0xf; i < (((uint32_t)&_kernel_data_end - 1) & ~0xf) + 0x10; i += 0x10) + write_mem_line(i); + logf(LOG_DUMP, "Kernel bss section:"); + last_line_mode = SECTION_START; + for (uint32_t i = 0x4000000; i < (((uint32_t)&_kernel_bss_end - 1) & ~0xf) + 1; i += 0x10) + write_mem_line(i); + logf(LOG_DUMP, "Kernel heap:"); + last_line_mode = SECTION_START; + const uint32_t first_heap_page = (((uint32_t)&_kernel_bss_end - 1) >> 12) + 1; + for (uint8_t n = first_heap_page & 7; n < 8; ++n) + if (*(uint8_t *)(0x40000 + (first_heap_page >> 3)) & (1 << n)) + write_mem_page((first_heap_page & ~7) | n); + for (uint8_t *i = (uint8_t *)(0x40000 + (first_heap_page >> 3) + 1); i < (uint8_t *)0x41000; ++i) + for (uint8_t n = 0; n < 8; ++n) + if (*i & (1 << n)) + write_mem_page((i - (uint8_t *)0x40000) * 8 + n); + + for (uint8_t t = 0; t < MAX_TASKS; ++t) + if (tasks[t].page_directory) { + logf(LOG_DUMP, "Task 0x%hb (%s)'s memory:", t + 1, tasks[t].name); + last_line_mode = SECTION_START; + const void *const pd = tasks[t].page_directory; + asm ( + "mov %0, %%cr3" + : : "a" (pd)); + for (uint32_t i = 0x08000000; i; i += 4096) + if (pd_is_mapped(pd, i)) + for (uint32_t j = i; j < i + 4096; j += 16) + write_mem_line(j); + } + break; + } + + logf(LOG_INFO, "Dumped state."); + + asm ( + "mov %0, %%cr3" + : : "a" (cr3)); +} \ No newline at end of file diff --git a/src/kernel/elf-link.ld b/src/kernel/elf-link.ld index 84d3f92..d0c6723 100644 --- a/src/kernel/elf-link.ld +++ b/src/kernel/elf-link.ld @@ -11,7 +11,9 @@ SECTIONS { *(.rodata) } .data : { + _kernel_data_start = .; *(.data) + _kernel_data_end = .; } . = 0x04000000; .bss : { diff --git a/src/kernel/elf.c b/src/kernel/elf.c index 146035e..f601654 100644 --- a/src/kernel/elf.c +++ b/src/kernel/elf.c @@ -6,6 +6,8 @@ #include "paging.h" #include "pmap.h" +#include "log.h" + #define ELF_MAGIC 0x464c457f enum { @@ -129,9 +131,12 @@ uint32_t try_elf_run(const struct drive *d, const char *path, const char *pass_o tstate.ret_addr = ehead.entry_vma; tstate.stack_bottom = 0; +//logf(LOG_INFO, " tasks: 0x%h", tasks); +//logf(LOG_INFO, "active_task: 0x%h", active_task); +//logf(LOG_INFO, " new edi: 0x%hb", active_task - tasks + 1); tstate.edx = (uint32_t)pass_vma; - tstate.esi = active_task - tasks + 1; - tstate.edi = io_handle; + tstate.esi = io_handle; + tstate.edi = active_task - tasks + 1; tstate.esp = 0; const char *path_end_start = path; diff --git a/src/kernel/idt.c b/src/kernel/idt.c index b8990f2..9b3ba96 100644 --- a/src/kernel/idt.c +++ b/src/kernel/idt.c @@ -35,25 +35,23 @@ struct { //file handles as (drive_number << 8) + file_id_t -uint32_t sc_open_file(uint32_t drive_number, char *path) { //not static to ensure sysv abi +uint32_t sc_open_file(uint32_t drive_number, char *path) { 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); } -void sc_close_file(uint32_t handle) { //not static to ensure sysv abi +void sc_close_file(uint32_t handle) { if (!handle) return; drives[handle >> 8].free_file(drives + (handle >> 8), handle & 0xff); } -uint32_t sc_file_get_size(uint32_t handle) { //not static to ensure sysv abi - //logf(LOG_INFO, "sc_file_get_size(%d)", handle); +uint32_t sc_file_get_size(uint32_t handle) { if (!handle) return 0; return drives[handle >> 8].get_file_length(drives + (handle >> 8), handle & 0xff); } -uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { //not static to ensure sysv abi +uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, void *buffer) { if (!handle) return 0; uint32_t len = sc_file_get_size(handle); @@ -63,14 +61,14 @@ uint32_t sc_file_read(uint32_t handle, uint32_t file_offset, uint32_t count, voi return count; } -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 +uint32_t sc_start_task(uint32_t drive_number, char *path, const char *pass, uint32_t io_task) { switch_to_kernel_cr3(); 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; } -void *sc_allocate_ram(uint32_t pages) { //not static to ensure sysv abi +void *sc_allocate_ram(uint32_t pages) { return pd_user_allocate_anywhere_writable(active_task->page_directory, pages); } @@ -83,7 +81,7 @@ enum mi_arg { }; __attribute__ ((pure)) -uint32_t sc_memory_info(enum mi_arg arg) { //not static to ensure sysv abi +uint32_t sc_memory_info(enum mi_arg arg) { switch (arg) { case MI_KERNEL_MAX: return max_kernel_pages; @@ -100,7 +98,7 @@ uint32_t sc_memory_info(enum mi_arg arg) { //not static to ensure sysv abi } } -void sc_wait_for_task(uint32_t handle) { //not static to ensure sysv abi +void sc_wait_for_task(uint32_t handle) { add_wait((struct wait){.mode = PROCESS_END, .task = tasks + handle - 1}); } @@ -108,11 +106,11 @@ uint32_t sc_enumerate_dir(uint32_t drive_number, const char *path, struct direct return drives[drive_number].enumerate_dir(drives + drive_number, path, buffer, max_entries); } -uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { //not static to ensure sysv abi +uint32_t sc_count_of_dir(uint32_t drive_number, const char *path) { 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 +void sc_get_next_window_action(struct window *w, struct window_action *action) { *action = next_window_action(w); } @@ -120,25 +118,27 @@ 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_wait_ipc_sent(uint32_t task_handle) { + add_wait((struct wait){.mode = IPC_SENT, .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_any_ipc_sent() { + add_wait((struct wait){.mode = IPC_SENT_ANY}); } void sc_wait_ipc_read(uint32_t handle) { - add_wait((struct wait){.mode = IPC_SEND, .task = tasks + handle - 1}); + add_wait((struct wait){.mode = IPC_READ, .task = tasks + handle - 1}); } +//returns a uint32_t to ensure upper twenty-four bits of +// eax are set to zero - otherwise userland stuff break __attribute__ ((pure)) -bool sc_is_task_running(uint32_t handle) { - return tasks[handle - 1].page_directory; +uint32_t sc_is_task_running(uint32_t handle) { + return tasks[handle - 1].page_directory ? 1 : 0; } void const *syscall_table[] = { @@ -162,8 +162,8 @@ void const *syscall_table[] = { &push_window_paint, &sc_get_next_window_action, &sc_wait_window_action, - &sc_wait_ipc, - &sc_wait_any_ipc, + &sc_wait_ipc_sent, + &sc_wait_any_ipc_sent, &find_unread_ipc, &sc_wait_ipc_read, &sc_is_task_running @@ -240,17 +240,11 @@ void exception_halt(uint32_t eax, uint32_t ebx, uint32_t ecx, } //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); - +bool pf_check_stack(uint32_t cr2) { 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 { diff --git a/src/kernel/isrs.asm b/src/kernel/isrs.asm index 02b046d..a4eb988 100644 --- a/src/kernel/isrs.asm +++ b/src/kernel/isrs.asm @@ -23,6 +23,7 @@ extern on_kbd_isr extern make_sure_tasks extern exception_halt extern pf_check_stack +extern dump n_syscalls equ 0x19 @@ -139,6 +140,17 @@ kbd_isr: call on_kbd_isr + test eax, eax + jz .no_debug + + push ebx + push esi + push edi + push eax + call dump + add esp, 16 + +.no_debug: mov al, 0x20 out 0x0020, al diff --git a/src/kernel/kbd.c b/src/kernel/kbd.c index f7158bb..c09684d 100644 --- a/src/kernel/kbd.c +++ b/src/kernel/kbd.c @@ -91,7 +91,7 @@ static inline uint8_t get_next_code_byte() { static enum key_modifiers_t keymods = 0; -void on_kbd_isr() { +enum kbd_isr_result on_kbd_isr() { //logf(LOG_INFO, "on_kbd_isr()"); while (inb(PS2_CMD) & PS2S_CODE_READY) { last_code_byte = 0; @@ -201,6 +201,9 @@ void on_kbd_isr() { break; } + if (!is_up && (entry == KEY_PAUSE) && (keymods & ALTS)) + return (keymods & SHIFTS) ? SHIFT_DUMP : DUMP; + on_action((struct window_action){ .action_type = is_up ? KEY_UP : KEY_DOWN, .as_key = (struct key_packet){ @@ -209,4 +212,5 @@ void on_kbd_isr() { } }); } + return NORMAL; } diff --git a/src/kernel/kbd.h b/src/kernel/kbd.h index e9affad..7e03fd7 100644 --- a/src/kernel/kbd.h +++ b/src/kernel/kbd.h @@ -1,11 +1,17 @@ #ifndef KBD_H #define KBD_H +#include #include #include void init_kbd(); -void on_kbd_isr(); + +enum kbd_isr_result { + NORMAL, + DUMP, + SHIFT_DUMP +} on_kbd_isr(); #endif diff --git a/src/kernel/log.c b/src/kernel/log.c index 8ef2baf..6bad1cc 100644 --- a/src/kernel/log.c +++ b/src/kernel/log.c @@ -14,6 +14,7 @@ void init_log() { static const char *const log_prefixes[] = { " [USER] ", " [INFO] ", + " [DUMP] ", " [WARN] ", "[ERROR] ", "[PANIC] ", @@ -42,6 +43,10 @@ void logf(enum log_level level, const char *format, ...) { case '%': logch('%'); break; + case 'c':; + const char c = (char)va_arg(args, uint32_t); + logch(c); + break; case 's':; const char *s = va_arg(args, const char *); while (*s) diff --git a/src/kernel/log.h b/src/kernel/log.h index c5c4da7..daf90dd 100644 --- a/src/kernel/log.h +++ b/src/kernel/log.h @@ -6,6 +6,7 @@ enum log_level { LOG_USER, LOG_INFO, + LOG_DUMP, LOG_WARN, LOG_ERROR, LOG_PANIC diff --git a/src/kernel/paging.c b/src/kernel/paging.c index fbc33de..4672788 100644 --- a/src/kernel/paging.c +++ b/src/kernel/paging.c @@ -34,7 +34,7 @@ static void pd_map(void *pd, uint32_t physical_addr, uint32_t virtual_addr, bool } __attribute__ ((pure)) -static bool pd_is_mapped(void *pd, uint32_t vma) { +bool pd_is_mapped(const void *pd, uint32_t vma) { uint32_t pde = ((uint32_t *)pd)[vma >> 22]; return (pde & PE_PRESENT) && (((uint32_t *)(pde & PE_ADDR_MASK))[(vma >> 12) % 1024] & PE_PRESENT); } @@ -52,8 +52,7 @@ void free_task_pd(void *pd) { free_pages(pd, 1); } -__attribute__ ((aligned (4096))) -static uint32_t kmap[KERNEL_END / 4096]; +#define kmap ((uint32_t *)0x00060000) void *new_task_pd() { uint32_t *pd = allocate_kernel_pages(1); diff --git a/src/kernel/paging.h b/src/kernel/paging.h index 6c1a6f5..082f6c2 100644 --- a/src/kernel/paging.h +++ b/src/kernel/paging.h @@ -12,4 +12,6 @@ void user_allocate_anywhere_readonly_together(void *pd, uint32_t pages, void **v void *vma_to_pma(void *pd, const void *vma) __attribute__ ((pure)); void switch_to_kernel_cr3(); -void switch_to_task_cr3(); \ No newline at end of file +void switch_to_task_cr3(); + +bool pd_is_mapped(const void *pd, uint32_t vma) __attribute__ ((pure)); \ No newline at end of file diff --git a/src/kernel/task.c b/src/kernel/task.c index ab08e6b..e2412e1 100644 --- a/src/kernel/task.c +++ b/src/kernel/task.c @@ -1,4 +1,5 @@ #include "paging.h" +#include "window.h" #include "panic.h" #include "pmap.h" #include "task.h" @@ -42,34 +43,15 @@ struct tss { #define TSS ((struct tss *)0x00004f98) -#define MAX_TASKS 64 - struct task_state tasks[MAX_TASKS]; struct task_state *active_task; -void init_tasks() { - active_task = tasks; - - for (uint8_t i = 0; i < MAX_TASKS; ++i) - tasks[i].page_directory = 0; - - TSS->ss0 = 0x18; - TSS->esp0 = 0x00040000; -//TSS->cs = 0x13; -//TSS->ds = 0x1b; -//TSS->ss = 0x1b; - TSS->iomp = sizeof(struct tss); - - asm volatile ( - "mov $0x08, %%ax\n" - "ltr %%ax" - : : : "ax"); -} - +//puts the handle into ecx 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].ecx = n + 1; tasks[n].waiting = false; for (uint8_t i = 0; i < MAX_WAITS; ++i) tasks[n].waits[i].mode = NONE; @@ -129,22 +111,47 @@ struct ipc_pipe { bool delete_when_empty; } ipc_pipes[MAX_IPC_PIPES]; +void init_tasks() { + active_task = tasks; + + for (uint8_t i = 0; i < MAX_TASKS; ++i) + tasks[i].page_directory = 0; + + for (uint16_t i = 0; i < MAX_IPC_PIPES; ++i) + ipc_pipes[i].buffer = 0; + + TSS->ss0 = 0x18; + TSS->esp0 = 0x00040000; +//TSS->cs = 0x13; +//TSS->ds = 0x1b; +//TSS->ss = 0x1b; + TSS->iomp = sizeof(struct tss); + + asm volatile ( + "mov $0x08, %%ax\n" + "ltr %%ax" + : : : "ax"); +} + void delete_pipe(struct ipc_pipe *pipe) { free_pages(pipe->buffer, IPC_BUFFER_PAGES); pipe->buffer = 0; } void delete_task(struct task_state *state) { +//logf(LOG_INFO, "-- deleting 0x%h", state); switch_to_kernel_cr3(); free_task_pd(state->page_directory); switch_to_task_cr3(); + + delete_any_windows_from(state); state->page_directory = 0; +//logf(LOG_INFO, "-- unwaiting any waiting for 0x%h", state); 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}); + unwait_any((struct wait){.mode = IPC_SENT, .task = state}); - const uint32_t handle = active_task - tasks + 1; + const uint32_t handle = state - tasks + 1; for (struct ipc_pipe *pipe = ipc_pipes; pipe < ipc_pipes + MAX_IPC_PIPES; ++pipe) if (pipe->buffer) { if (pipe->reader_handle == handle) @@ -158,15 +165,19 @@ void delete_task(struct task_state *state) { } } +__attribute__ ((pure)) 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)) + (pipe->buffer_next_read != pipe->buffer_next_send)) { + //logf(LOG_INFO, "found %d bytes of unread ipc from 0x%hb to 0x%hb", pipe->buffer_next_send - pipe->buffer_next_read + (pipe->buffer_next_read < pipe->buffer_next_send ? 0 : IPC_BUFFER_PAGES * 4096), pipe->sender_handle, pipe->reader_handle); return pipe->sender_handle; + } return 0; } +__attribute__ ((pure)) 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) && @@ -176,7 +187,7 @@ struct ipc_pipe *get_existing_pipe(uint32_t sender_handle, uint32_t reader_handl } uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer) { - if (!reader_handle || !tasks[reader_handle - 1].page_directory) + if (!reader_handle || (reader_handle > MAX_TASKS) || !tasks[reader_handle - 1].page_directory) return -1; const uint32_t our_handle = active_task - tasks + 1; @@ -197,8 +208,8 @@ uint32_t ipc_send(uint32_t reader_handle, uint32_t count, const void *buffer) { 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}); + unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_SENT, .task = active_task}); + unwait(tasks + reader_handle - 1, (struct wait){.mode = IPC_SENT_ANY}); uint32_t send_left = pipe->buffer_next_read - pipe->buffer_next_send - 1; if (send_left < 0) @@ -220,17 +231,34 @@ 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) { - if (!sender_handle || !tasks[sender_handle - 1].page_directory) +//logf(LOG_INFO, "kernel ipc_read(0x%hb, %u, 0x%h)", sender_handle, count, buffer); + if (!sender_handle || (sender_handle > MAX_TASKS)) return -1; const uint32_t our_handle = active_task - tasks + 1; - struct ipc_pipe *pipe = get_existing_pipe(sender_handle, our_handle); + struct ipc_pipe *const pipe = get_existing_pipe(sender_handle, our_handle); if (!pipe) - return 0; + return tasks[sender_handle - 1].page_directory ? 0 : -1; - unwait(tasks + sender_handle - 1, (struct wait){.mode = IPC_SEND, .task = active_task}); +//logf(LOG_INFO, "found pipe from 0x%hb to 0x%hb", pipe->sender_handle, pipe->reader_handle); - //TODO + unwait(tasks + sender_handle - 1, (struct wait){.mode = IPC_READ, .task = active_task}); + + uint8_t *write_to = buffer; + const uint8_t *read_from = pipe->buffer_next_read; + + //change this to memcpys like ipc_send once memcpy is more efficient + while ((read_from != pipe->buffer_next_send) && count--) { + *(write_to++) = *(read_from++); + if (read_from == pipe->buffer + IPC_BUFFER_PAGES * 4096) + read_from = pipe->buffer; + } + + if (pipe->delete_when_empty && (read_from == pipe->buffer_next_send)) + delete_pipe(pipe); + else + pipe->buffer_next_read = read_from; + return write_to - (uint8_t *)buffer; } void add_wait(struct wait wait) { @@ -257,12 +285,13 @@ void unwait(struct task_state *task, struct wait wait) { continue; switch (wait.mode) { case PROCESS_END: - case IPC_RECEIVE: + case IPC_SENT: + case IPC_READ: if (task->waits[i].task != wait.task) continue; break; case WINDOW_ACTION: - case IPC_RECEIVE_ANY: + case IPC_SENT_ANY: break; default: PANIC("Unwait matched with unrecognized wait mode."); @@ -272,4 +301,4 @@ void unwait(struct task_state *task, struct wait wait) { task->waiting = false; return; } -} \ No newline at end of file +} diff --git a/src/kernel/task.h b/src/kernel/task.h index 574dfa7..643c88e 100644 --- a/src/kernel/task.h +++ b/src/kernel/task.h @@ -4,17 +4,18 @@ #include #include -#define TASK_NAME_LEN 15 +#define TASK_NAME_LEN 86 #define MAX_WAITS 16 +#define MAX_TASKS 64 struct wait { enum { NONE, PROCESS_END, WINDOW_ACTION, - IPC_RECEIVE, - IPC_RECEIVE_ANY, - IPC_SEND + IPC_SENT, + IPC_SENT_ANY, + IPC_READ } mode; union { struct task_state *task; @@ -50,6 +51,7 @@ extern struct task_state *active_task; void init_tasks(); +//puts the handle into ecx uint32_t new_task(struct task_state state); void advance_active_task(); @@ -58,6 +60,6 @@ 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(); +uint32_t find_unread_ipc() __attribute__ ((pure)); #endif \ No newline at end of file diff --git a/src/kernel/window.c b/src/kernel/window.c index 28798d1..078a194 100644 --- a/src/kernel/window.c +++ b/src/kernel/window.c @@ -99,7 +99,8 @@ got_window: return w; } -void del_window(struct window *w) { +static void del_no_paint(struct window *w) { +//logf(LOG_INFO, "-- deleting window 0x%h", w); if (w == top_window) top_window = w->below; if (w == bottom_window) @@ -109,17 +110,37 @@ void del_window(struct window *w) { if (w->above) w->above->below = w->below; +//logf(LOG_INFO, " -- action buffer was 0x%h", w->action_buffer); free_pages(w->action_buffer, ACTION_BUFFER_PAGES); w->pixel_buffer_pma = 0; +} +void del_window(struct window *w) { + del_no_paint(w); paint_all(); } -void resize_window(struct window *w, uint16_t width, uint16_t height) { +void delete_any_windows_from(struct task_state *tstate) { +//logf(LOG_INFO, "-- deleting windows from 0x%h", tstate); + bool need_to_paint = false; + for (struct window *w = windows; w < windows + MAX_WINDOWS; ++w) + if (w->pixel_buffer_pma && (w->from_task == tstate)) { + //logf(LOG_INFO, " -- found match at 0x%h", w); + del_no_paint(w); + need_to_paint = true; + } + if (need_to_paint) { + //logf(LOG_INFO, "-- trying to paint after deleting windows"); + paint_all(); + } +} + +void resize_window(struct window *w, uint16_t width, uint16_t height, const void *pixel_buffer) { const bool smaller = (width < w->width) || (height < w->height); w->width = width; w->height = height; + reassign_pixel_buffer(w, pixel_buffer); if (smaller) paint_all(); diff --git a/src/kernel/window.h b/src/kernel/window.h index 60b81ea..0aa9b0f 100644 --- a/src/kernel/window.h +++ b/src/kernel/window.h @@ -5,6 +5,8 @@ #include +#include "task.h" + struct window; void paint_bg(); @@ -12,7 +14,7 @@ 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 resize_window(struct window *w, uint16_t width, uint16_t height, const void *pixel_buffer); 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); @@ -20,4 +22,6 @@ void wait_window_action(); void on_action(struct window_action packet); +void delete_any_windows_from(struct task_state *tstate); + #endif diff --git a/src/user/hello/hello.asm b/src/user/hello/hello.asm new file mode 100644 index 0000000..cc0645a --- /dev/null +++ b/src/user/hello/hello.asm @@ -0,0 +1,28 @@ +bits 32 + +global _entry + +section .text +_entry: + mov eax, 0x05 + mov ebx, esi + mov ecx, data.len + mov edx, data + int 0x30 + + int 0x38 + +section .rodata +data: + dd 0xb + dd .str_len + dd 0 + +.str: + db "Hello, world!", 0x0a +.str_len equ $ - .str + + dd 0x02 + dd 0 + dd 0 +.len equ $ - data \ No newline at end of file diff --git a/src/user/highway/cmds.c b/src/user/highway/cmds.c index 0420ae1..53198df 100644 --- a/src/user/highway/cmds.c +++ b/src/user/highway/cmds.c @@ -1,4 +1,4 @@ -#include +#include #include diff --git a/src/user/highway/line.c b/src/user/highway/line.c index bf171e5..cefdf92 100644 --- a/src/user/highway/line.c +++ b/src/user/highway/line.c @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -20,7 +20,7 @@ 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( + term_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]) ); @@ -32,6 +32,7 @@ static void line_replace(const char *from) { while (*fi) { if (ti == line + LINE_SIZE) { term_add_sz("Line too long.\n"); + term_paint(); line[0] = '\0'; return; } @@ -49,11 +50,13 @@ static void line_replace(const char *from) { term_addf("Unterminated variable at\"%10s...\".\n", fi); else term_addf("Unterminated variable at \"%s\".\n", fi); + term_paint(); line[0] = '\0'; return; } if (ti + (var_end - var_start) >= line + LINE_SIZE) { term_add_sz("Line too long.\n"); + term_paint(); line[0] = '\0'; return; } @@ -87,16 +90,17 @@ void run_line(const char *original_line) { else if (blockequ(line, "echo ", 5)) { term_add_sz(space + 1); term_add_char('\n'); + term_paint(); } else if (blockequ(line, "vars", 5)) dump_vars(); - else if (blockequ(line, "quit", 5)) { - del_term(active_term); + else if (blockequ(line, "quit", 5)) __pcrt_quit(); + else if (blockequ(line, "clear", 6)) { + term_clear(); + term_paint(); } - else if (blockequ(line, "clear", 6)) - clear_term(); - else if (blockequ(line, "help", 5)) + else if (blockequ(line, "help", 5)) { 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" @@ -105,10 +109,13 @@ void run_line(const char *original_line) { " vars\t\t\t" "dump variables\n" " quit\t\t\t" "exit highway\n" " help\t\t\t" "show this\n"); + term_paint(); + } 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) { term_add_sz("Could not run command.\n"); + term_paint(); return; } for (uint16_t to_i = LINE_SIZE - 1; to_i >= path->length; --to_i) @@ -116,14 +123,17 @@ void run_line(const char *original_line) { blockcpy(line, path->data, path->length); if (!try_run_command_blocking(line, stdio_task)) { term_add_sz("Could not run command.\n"); + term_paint(); return; } else { + _yield_task(); + term_add_char('\n'); ensure_color(); - if (active_term->cursor_x) - term_newline(); } } - else + else { + _yield_task(); ensure_color(); + } } \ No newline at end of file diff --git a/src/user/highway/main.c b/src/user/highway/main.c index 60d5a69..c9ceee2 100644 --- a/src/user/highway/main.c +++ b/src/user/highway/main.c @@ -1,32 +1,21 @@ -#include -#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; +//syslogf(" this task: 0x%2h", this_task); +//syslogf(" stdio task: 0x%2h", stdio_task); +//syslogf("calling task: 0x%2h", calling_task); source(*arg ? arg : "user/default.rc"); ensure_color(); term_add_sz("Portland Highway\nType \"help\" for help.\n"); - paint_term(); + term_paint(); char cmd_buf[128]; while (1) { diff --git a/src/user/highway/vars.c b/src/user/highway/vars.c index 5f56621..82062c4 100644 --- a/src/user/highway/vars.c +++ b/src/user/highway/vars.c @@ -1,4 +1,4 @@ -#include +#include #include #include @@ -77,6 +77,7 @@ void del_var(struct no_null_sn name) { void dump_vars() { for (struct var_dict_node *node = var_dict_start; node; node = node->next) { - term_addf_no_ww("$%ns$ = %ns\n", node->name.length, node->name.data, node->value.length, node->value.data); + term_addf_no_ww("$%ns$\t= %ns\n", node->name.length, node->name.data, node->value.length, node->value.data); + term_paint(); } } \ No newline at end of file diff --git a/src/user/include/knob/ipc.h b/src/user/include/knob/ipc.h index 3eab562..335959d 100644 --- a/src/user/include/knob/ipc.h +++ b/src/user/include/knob/ipc.h @@ -5,7 +5,7 @@ //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); +uint32_t try_send_ipc(_task_handle_t to, const void *buffer, uint32_t size); //blocking, returns early if other process is dead. //return value is number of bytes read. diff --git a/src/user/include/libterm/command.h b/src/user/include/libterm/command.h new file mode 100644 index 0000000..7587306 --- /dev/null +++ b/src/user/include/libterm/command.h @@ -0,0 +1,68 @@ +#ifndef LIBTERM_COMMAND_H +#define LIBTERM_COMMAND_H + +#include + +#include + +#include + +#include +#include + +//set to stdio task by default +extern _task_handle_t term_task; + +struct terminal_command { + enum { + SET_DIMENSIONS, + GET_DIMENSIONS, + PAINT, + CLEAR, + SET_COLOR, + SET_CURSOR, + CURSOR_LEFT, + CURSOR_RIGHT, + CURSOR_UP, + CURSOR_DOWN, + ADD_CHAR, + ADD_SN, + ADD_SN_NO_WORDWRAP, + GET_KEY + } kind; + + union { + struct { + uint32_t y; + uint32_t x; + } as_coords; + struct { + uint8_t fg; + uint8_t bg; + } as_color; + char as_char; + uint32_t as_uint; + }; +} __attribute__ ((__packed__)); + +union terminal_response { + struct { + uint32_t y; + uint32_t x; + } as_coords; + struct key_packet as_key; +} __attribute__ ((__packed__)); + +//returns false if terminal has died +static inline bool try_send_command(struct terminal_command *cmd) { + return try_send_ipc(term_task, cmd, sizeof(struct terminal_command)) + == sizeof(struct terminal_command); +} + +//returns false if terminal has died +static inline bool try_get_response(union terminal_response *rs) { + return try_read_ipc(term_task, rs, sizeof(union terminal_response)) + == sizeof(union terminal_response); +} + +#endif \ No newline at end of file diff --git a/src/user/include/libterm/readline.h b/src/user/include/libterm/readline.h new file mode 100644 index 0000000..b1d5b0a --- /dev/null +++ b/src/user/include/libterm/readline.h @@ -0,0 +1,10 @@ +#ifndef LIBTERM_READLINE_H +#define LIBTERM_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/libterm/terminal.h b/src/user/include/libterm/terminal.h new file mode 100644 index 0000000..19bd517 --- /dev/null +++ b/src/user/include/libterm/terminal.h @@ -0,0 +1,35 @@ +#ifndef LIBTERM_TERMINAL_H +#define LIBTERM_TERMINAL_H + +#include + +#include +#include + +void term_set_dimensions(uint32_t width, uint32_t height); +void term_get_dimensions(uint32_t *width, uint32_t *height); + +void term_paint(); +void term_clear(); + +void term_set_color(uint8_t fg, uint8_t bg); +void term_set_cursor(uint32_t new_y, uint32_t new_x); + +void term_cursor_left(); +void term_cursor_right(); +void term_cursor_up(); +void term_cursor_down(); + +void term_add_char(char ch); +void term_add_sn_no_ww(const char *s, uint32_t n); +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, ...); + +struct key_packet term_get_key_blocking(); + +#endif \ No newline at end of file diff --git a/src/user/include/pland/pcrt.h b/src/user/include/pland/pcrt.h index 42158cd..795738e 100644 --- a/src/user/include/pland/pcrt.h +++ b/src/user/include/pland/pcrt.h @@ -17,5 +17,6 @@ void __pcrt_quit() __attribute__ ((noreturn)); extern _task_handle_t calling_task; extern _task_handle_t stdio_task; +extern _task_handle_t this_task; #endif diff --git a/src/user/include/pland/syscall.h b/src/user/include/pland/syscall.h index 6d327d5..6870865 100644 --- a/src/user/include/pland/syscall.h +++ b/src/user/include/pland/syscall.h @@ -39,8 +39,8 @@ enum _scn { _SCN_PAINT_WINDOW, _SCN_GET_WIN_ACTION, _SCN_WAIT_FOR_ACTION, - _SCN_WAIT_IPC_SEND, - _SCN_WAIT_FOR_ANY_IPC, + _SCN_WAIT_IPC_SENT, + _SCN_WAIT_ANY_IPC_SENT, _SCN_FIND_UNREAD_IPC, _SCN_WAIT_IPC_READ, _SCN_IS_TASK_RUNNING @@ -137,7 +137,7 @@ static inline uint32_t _ipc_send(_task_handle_t handle, uint32_t count, const vo } 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); + return _sc3(_SCN_IPC_READ, handle, count, (uint32_t)buffer); } static inline void *_allocate_ram(uint32_t pages) { @@ -184,11 +184,11 @@ 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 _resize_window(_window_handle_t window, uint16_t width, uint16_t height, const void *pixel_buffer) { + _sc4(_SCN_RESIZE_WINDOW, (uint32_t)window, width, height, (uint32_t)pixel_buffer); } -static inline void _reassign_pixbuf(_window_handle_t window, void *pixel_buffer) { +static inline void _reassign_pixbuf(_window_handle_t window, const void *pixel_buffer) { _sc2(_SCN_REASSIGN_PIXBUF, (uint32_t)window, (uint32_t)pixel_buffer); } @@ -204,16 +204,16 @@ 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 _wait_ipc_sent(_task_handle_t sending_task) { + _sc1(_SCN_WAIT_IPC_SENT, 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 void _wait_for_any_ipc_sent() { + _sc0(_SCN_WAIT_ANY_IPC_SENT); } static inline _task_handle_t _find_unread_ipc() { diff --git a/src/user/include/popups/popup.h b/src/user/include/popups/popup.h index 1a3c531..9a39997 100644 --- a/src/user/include/popups/popup.h +++ b/src/user/include/popups/popup.h @@ -11,8 +11,7 @@ struct popup { struct key_packet quit_as; //terminated by one with .key_id == 0 - struct key_packet *quit_binds; - bool free_quit_binds; + const struct key_packet *quit_binds; }; void handle_actions(struct popup *p); diff --git a/src/user/include/terminal/readline.h b/src/user/include/terminal/readline.h deleted file mode 100644 index 9046610..0000000 --- a/src/user/include/terminal/readline.h +++ /dev/null @@ -1,10 +0,0 @@ -#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 deleted file mode 100644 index 1782173..0000000 --- a/src/user/include/terminal/terminal.h +++ /dev/null @@ -1,57 +0,0 @@ -#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/knob/format.c b/src/user/knob/format.c index 54d50ef..c5d2447 100644 --- a/src/user/knob/format.c +++ b/src/user/knob/format.c @@ -81,6 +81,8 @@ static const char *get_format(const char *from, struct format_spec *format_out) return from + 1; } +//char debug[] = "-- format_v: fmt = \" \"..."; + //allocates new memory char *format_v(const char *fmt, va_list args) { buf = get_block(FORMAT_BUF_INIT_SIZE); @@ -90,6 +92,11 @@ char *format_v(const char *fmt, va_list args) { buf_i = buf; while (*fmt) { + //debug[20] = *fmt; + //debug[21] = fmt[1]; + //debug[22] = fmt[2]; + //_system_log(debug); + if (*fmt != '%') { ensure(1); *(buf_i++) = *(fmt++); @@ -133,11 +140,15 @@ char *format_v(const char *fmt, va_list args) { case UNSIGNED_DECIMAL: k = va_arg(args, uint32_t); if (!form.len) { - uint32_t n = 10; - ++form.len; - while (k >= n) { + if (k >= 1000000000) + form.len = 10; + else { + uint32_t n = 10; ++form.len; - n *= 10; + while (k >= n) { + ++form.len; + n *= 10; + } } } ensure(form.len); diff --git a/src/user/knob/ipc.c b/src/user/knob/ipc.c index dbf1a22..5ca4bb4 100644 --- a/src/user/knob/ipc.c +++ b/src/user/knob/ipc.c @@ -2,10 +2,12 @@ //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) { +uint32_t try_send_ipc(_task_handle_t to, const void *buffer, uint32_t size) { const uint32_t size_backup = size; while (size) { + //syslogf("_ipc_send(0x%2h, 0x%h, %u)", to, buffer, size); uint32_t res = _ipc_send(to, size, buffer); + //syslogf("=> %u", res); if (!res) { _wait_ipc_read(to); _yield_task(); @@ -17,16 +19,19 @@ uint32_t try_send_ipc(_task_handle_t to, void *buffer, uint32_t size) { buffer += res; } } + return size_backup; } //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) { +uint32_t try_read_ipc(_task_handle_t from, void *buffer, uint32_t size) { const uint32_t size_backup = size; while (size) { + //syslogf("_ipc_read(0x%2h, 0x%h, %u)", from, buffer, size); uint32_t res = _ipc_read(from, size, buffer); + //syslogf("=> %u", res); if (!res) { - _wait_ipc_send(from); + _wait_ipc_sent(from); _yield_task(); } else if (res == -1) @@ -36,6 +41,7 @@ uint32_t read_ipc(_task_handle_t from, void *buffer, uint32_t size) { buffer += res; } } + return size_backup; } void flush_ipc(_task_handle_t from) { diff --git a/src/user/knob/task.c b/src/user/knob/task.c index 3bf3e85..9a49386 100644 --- a/src/user/knob/task.c +++ b/src/user/knob/task.c @@ -1,9 +1,12 @@ -#include #include #include #include #include +#include + +#include + _task_handle_t run_command(const char *path, _task_handle_t stdio_task) { uint8_t dn; path = remove_prefix(path, &dn); @@ -14,9 +17,9 @@ _task_handle_t run_command(const char *path, _task_handle_t stdio_task) { blockcpy(new_path, path, ptr - path); new_path[ptr - path] = '\0'; - bool succeded = _start_task(dn, new_path, ptr + 1, stdio_task); + _task_handle_t handle = _start_task(dn, new_path, ptr + 1, stdio_task); free_block(new_path); - return succeded; + return handle; } return _start_task(dn, path, "", stdio_task); @@ -24,11 +27,12 @@ _task_handle_t run_command(const char *path, _task_handle_t stdio_task) { bool try_run_command_blocking(const char *path, _task_handle_t stdio_task) { _task_handle_t handle = run_command(path, stdio_task); - if (!handle) + if (!handle) { return false; - while (_is_task_running(handle)) { + } + do { _wait_for_task(handle); _yield_task(); - } + } while (_is_task_running(handle)); return true; } \ No newline at end of file diff --git a/src/user/libterm/readline.c b/src/user/libterm/readline.c new file mode 100644 index 0000000..b37801d --- /dev/null +++ b/src/user/libterm/readline.c @@ -0,0 +1,106 @@ +#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) { + term_add_sz(prompt); + term_add_char(' '); + term_paint(); + + uint32_t l = 0; + uint32_t c = 0; + + while (1) { + struct key_packet kp = term_get_key_blocking(); + switch (kp.key_id) { + case KEY_LEFT_ARROW: + if (c) { + --c; + term_cursor_left(); + term_paint(); + } + continue; + case KEY_RIGHT_ARROW: + if (c != l) { + ++c; + term_cursor_right(); + term_paint(); + } + continue; + case KEY_HOME: + while (c) { + --c; + term_cursor_left(); + } + term_paint(); + continue; + case KEY_END: + while (c != l) { + ++c; + term_cursor_right(); + } + term_paint(); + continue; + case KEY_DELETE: + if (c != l) { + ++c; + term_cursor_right(); + } + case KEY_BSPACE: + if (!c) + continue; + --c; + --l; + for (uint32_t i = c; i < l; ++i) + sz[i] = sz[i + 1]; + term_cursor_left(); + term_add_sn_no_ww(sz + c, l - c); + term_add_char(' '); + for (uint32_t i = l + 1; i > c; --i) + term_cursor_left(); + term_paint(); + continue; + case KEY_ENTER: + while (c != l) { + ++c; + term_cursor_right(); + } + sz[l] = '\0'; + term_add_char('\n'); + term_paint(); + return l; + default: + if (l == max_length) + continue; + char ch = key_to_char(kp); + if (!ch) + continue; + if (c == l) { + ++l; + term_add_char(sz[c++] = ch); + term_paint(); + continue; + } + if (!(kp.modifiers & INSERT)) { + term_add_char(sz[c++] = ch); + term_paint(); + continue; + } + for (uint32_t i = l; i > c; --i) + sz[i] = sz[i - 1]; + sz[c] = ch; + ++l; + term_add_sn_no_ww(sz + c, l - c); + ++c; + for (uint32_t i = l; i > c; --i) + term_cursor_left(); + term_paint(); + continue; + } + } +} \ No newline at end of file diff --git a/src/user/libterm/terminal.c b/src/user/libterm/terminal.c new file mode 100644 index 0000000..387d63f --- /dev/null +++ b/src/user/libterm/terminal.c @@ -0,0 +1,179 @@ +#include + +#include +#include +#include + +_task_handle_t term_task; + +void term_set_dimensions(uint32_t width, uint32_t height) { + struct terminal_command cmd = { + .kind = SET_DIMENSIONS, + .as_coords = { + .x = width, + .y = height + } + }; + + try_send_command(&cmd); +} + +void term_get_dimensions(uint32_t *width, uint32_t *height) { + struct terminal_command cmd = { + .kind = GET_DIMENSIONS + }; + + if (try_send_command(&cmd)) { + union terminal_response rs; + if (try_get_response(&rs)) { + *width = rs.as_coords.x; + *height = rs.as_coords.y; + } + } +} + +void term_paint() { + struct terminal_command cmd = { + .kind = PAINT + }; + + try_send_command(&cmd); +} + +void term_clear() { + struct terminal_command cmd = { + .kind = CLEAR + }; + + try_send_command(&cmd); +} + +void term_set_color(uint8_t fg, uint8_t bg) { + struct terminal_command cmd = { + .kind = SET_COLOR, + .as_color = { + .fg = fg, + .bg = bg + } + }; + + try_send_command(&cmd); +} + +void term_set_cursor(uint32_t new_y, uint32_t new_x) { + struct terminal_command cmd = { + .kind = SET_CURSOR, + .as_coords = { + .y = new_y, + .x = new_x + } + }; + + try_send_command(&cmd); +} + +void term_cursor_left() { + struct terminal_command cmd = { + .kind = CURSOR_LEFT + }; + + try_send_command(&cmd); +} + +void term_cursor_right() { + struct terminal_command cmd = { + .kind = CURSOR_RIGHT + }; + + try_send_command(&cmd); +} + +void term_cursor_up() { + struct terminal_command cmd = { + .kind = CURSOR_UP + }; + + try_send_command(&cmd); +} + +void term_cursor_down() { + struct terminal_command cmd = { + .kind = CURSOR_DOWN + }; + + try_send_command(&cmd); +} + +void term_add_char(char ch) { + struct terminal_command cmd = { + .kind = ADD_CHAR, + .as_char = ch + }; + + try_send_command(&cmd); +} + +void term_add_sn_no_ww(const char *s, uint32_t n) { + struct terminal_command cmd = { + .kind = ADD_SN_NO_WORDWRAP, + .as_uint = n + }; + + if (try_send_command(&cmd)) + try_send_ipc(term_task, s, n); +} + +void term_add_sz_no_ww(const char *sz) { + term_add_sn_no_ww(sz, strlen(sz)); +} + +void term_add_sz(const char *sz) { + const uint32_t len = strlen(sz); + + struct terminal_command cmd = { + .kind = ADD_SN, + .as_uint = len + }; + + if (try_send_command(&cmd)) + try_send_ipc(term_task, sz, len); +} + +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); +} + +struct key_packet term_get_key_blocking() { + struct terminal_command cmd = { + .kind = GET_KEY + }; + + try_send_command(&cmd); + + union terminal_response rs; + try_get_response(&rs); + + return rs.as_key; +} diff --git a/src/user/libterm/termtask.c b/src/user/libterm/termtask.c new file mode 100644 index 0000000..cc853a6 --- /dev/null +++ b/src/user/libterm/termtask.c @@ -0,0 +1,9 @@ +#include + +#include + +void set_term_task_to_stdio() { + term_task = stdio_task; +} + +BEFORE_MAIN(set_term_task_to_stdio); \ No newline at end of file diff --git a/src/user/popups/info.c b/src/user/popups/info.c index 81a09e9..58903c8 100644 --- a/src/user/popups/info.c +++ b/src/user/popups/info.c @@ -43,7 +43,6 @@ void info_popup(struct popup *into, const char *msg, uint8_t fg, uint8_t bg) { 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; diff --git a/src/user/popups/popup.c b/src/user/popups/popup.c index d214f81..9cdccb4 100644 --- a/src/user/popups/popup.c +++ b/src/user/popups/popup.c @@ -30,8 +30,6 @@ void handle_actions(struct popup *p) { 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) { diff --git a/src/user/runtimes/c/pcrt.asm b/src/user/runtimes/c/pcrt.asm index 85c898c..0f06236 100644 --- a/src/user/runtimes/c/pcrt.asm +++ b/src/user/runtimes/c/pcrt.asm @@ -4,6 +4,7 @@ global __pcrt_entry global __pcrt_quit global calling_task global stdio_task +global this_task extern main extern __pcrt_before_main_start @@ -13,8 +14,9 @@ extern __pcrt_before_quit_end section .text __pcrt_entry: - mov dword [calling_task], esi - mov dword [stdio_task], edi + mov dword [calling_task], edi + mov dword [stdio_task], esi + mov dword [this_task], ecx push edx mov ebx, __pcrt_before_main_start @@ -42,4 +44,5 @@ __pcrt_quit: section .bss calling_task resd 1 -stdio_task resd 1 \ No newline at end of file +stdio_task resd 1 +this_task resd 1 \ No newline at end of file diff --git a/src/user/terminal/main.c b/src/user/terminal/main.c new file mode 100644 index 0000000..15ca6a1 --- /dev/null +++ b/src/user/terminal/main.c @@ -0,0 +1,373 @@ +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#define FONT_HARDCODE "berry" + +_window_handle_t window; +uint8_t *pixbuf; +char *termbuf; +struct font_info *font; + +uint32_t width; +uint32_t height; +uint32_t cols = 50; +uint32_t rows = 15; + +uint32_t cursor_y = 0; +uint32_t cursor_x = 0; + +uint8_t bg_color = 0x10; +uint8_t fg_color = 0x07; + +struct waiting_for_key_record { + _task_handle_t task; + struct waiting_for_key_record *next; +} *first_key_waiting = 0, *last_key_waiting = 0; + +static void draw_char(uint32_t y, uint32_t x, bool inverted) { +//syslogf("drawing 0x%2h%s at %u, %u", termbuf[y * cols + x], inverted ? " inverted" : "", y, x); + put_char(font, termbuf[y * cols + x], pixbuf + y * font->space_height * width + x * font->space_width, width, inverted ? fg_color : bg_color, inverted ? bg_color : fg_color); +} + +static void clear() { + for (uint32_t i = 0; i < cols * rows; ++i) + termbuf[i] = ' '; + for (uint32_t i = 0; i < width * height; ++i) + pixbuf[i] = bg_color; +} + +static void scroll_fw() { + uint32_t i; + for (i = 0; i < cols * (rows - 1); ++i) + termbuf[i] = termbuf[i + cols]; + for (; i < cols * rows; ++i) + termbuf[i] = ' '; + const uint32_t row_height = font->space_height; + for (i = 0; i < width * (height - row_height); ++i) + pixbuf[i] = pixbuf[i + width * row_height]; + for (; i < width * height; ++i) + pixbuf[i] = bg_color; +} + +static void cursor_down() { + if (cursor_y == rows - 1) + scroll_fw(); + else + ++cursor_y; +} + +static void cursor_right() { + if (cursor_x == cols - 1) { + cursor_x = 0; + cursor_down(); + } + else + ++cursor_x; +} + +__attribute__ ((pure)) +static uint32_t word_len(const char *sz) { + const char *const back = sz; + while ((*sz != ' ') && (*sz != '\n') && *sz && (*sz != '\t')) + ++sz; + return sz - back; +} + +#define MIN_TAB 3 +#define TAB_STOP 4 + +static void on_newline() { + draw_char(cursor_y, cursor_x, false); + cursor_x = 0; + cursor_down(); +} + +static void add_char(char ch); + +static void on_tab() { + for (uint32_t i = 0; i < MIN_TAB; ++i) + add_char(' '); + while (cursor_x % TAB_STOP) + add_char(' '); +} + +static void add_char(char ch) { + if (ch == '\n') + on_newline(); + else if (ch == '\t') + on_tab(); + else { + termbuf[cursor_y * cols + cursor_x] = ch; + draw_char(cursor_y, cursor_x, false); + cursor_right(); + } +} + +static void add_sz_no_ww(const char *sz) { + while (*sz) + add_char(*(sz++)); +} + +static void add_sn_no_ww(const char *sz, uint32_t l) { + for (uint32_t i = 0; i < l; ++i) + add_char(sz[i]); +} + +static void add_sz_ww(const char *sz) { + while (*sz) { + if (*sz == ' ') { + ++sz; + continue; + } + if (*sz == '\n') { + on_newline(); + ++sz; + continue; + } + if (*sz == '\t') { + on_tab(); + ++sz; + continue; + } + + if (cursor_x) + add_char(' '); + + const uint32_t len = word_len(sz); + + if ((len > cols - cursor_x) && (len <= cols)) { + cursor_x = 0; + cursor_down(); + } + add_sn_no_ww(sz, len); + + sz += len; + } +} + +char *const sz_empty_backup = ""; +char *sz_from_task = 0; +uint32_t sz_buf_size = 0; + +#define BUF_INCREMENTS 1024 + +static void get_sn(uint32_t len, _task_handle_t from) { + if (sz_buf_size <= len) { + if (sz_from_task && (sz_from_task != sz_empty_backup)) + free_block(sz_from_task); + sz_from_task = get_block(sz_buf_size += 1024); + if (!sz_from_task) { + add_sz_ww("Could not allocate enough memory for sent string. Treating as empty string.\n"); + sz_buf_size = 0; + sz_from_task = sz_empty_backup; + return; + } + } + + const uint32_t real_len = try_read_ipc(from, sz_from_task, len); + sz_from_task[real_len] = '\0'; +} + +static void set_dimensions(uint32_t new_rows, uint32_t new_cols) { + free_block(termbuf); + free_block(pixbuf); + //from here until _resize, the kernel may draw garbage if it + // needs to redraw the window. it won't page fault though. + + rows = new_rows; + cols = new_cols; + termbuf = get_block(rows * cols); + + width = cols * font->space_width; + height = cols * font->space_height; + pixbuf = get_block(width * height); + + cursor_y = 0; + cursor_x = 0; + clear(); + + _resize_window(window, width, height, pixbuf); +} + +void draw_all() { + for (uint32_t y = 0; y < rows; ++y) + for (uint32_t x = 0; x < cols; ++x) + draw_char(y, x, false); + draw_char(cursor_y, cursor_x, true); +} + +//#include + +void main(const char *cmd) { +//syslogf(" this task: 0x%2h", this_task); +//syslogf(" stdio task: 0x%2h", stdio_task); +//syslogf("calling task: 0x%2h", calling_task); + + font = get_font(FONT_HARDCODE); + if (!font) + return; + + termbuf = get_block(cols * rows); + width = cols * font->space_width; + height = rows * font->space_height; + pixbuf = get_block(width * height); + clear(); + add_sz_ww("Portland Terminal\n"); + window = _new_window(width, height, pixbuf); + _paint_window(window); + + _task_handle_t child_handle = run_command(cmd, this_task); + if (!child_handle) { + add_sz_ww("Failed to run passed command. Press any key to close.\n"); + _paint_window(window); + while (1) { + struct window_action action; + _get_win_action(window, &action); + if (action.action_type == NOT_READY) { + _wait_for_action(); + _yield_task(); + } + else if (action.action_type == KEY_DOWN) + return; + } + } + + while (1) { + if (first_key_waiting) { + struct window_action action; + _get_win_action(window, &action); + if (action.action_type == KEY_DOWN) { + union terminal_response rs = { + .as_key = action.as_key + }; + try_send_ipc(first_key_waiting->task, &rs, sizeof(union terminal_response)); + free_block(first_key_waiting); + first_key_waiting = first_key_waiting->next; + if (!first_key_waiting) + last_key_waiting = 0; + continue; + } + } + + _task_handle_t from = _find_unread_ipc(); + if (!from) { + if (!_is_task_running(child_handle)) + return; + + _wait_for_action(); + _wait_for_any_ipc_sent(); + _wait_for_task(child_handle); + _yield_task(); + continue; + } + + struct terminal_command request; + const uint32_t read = try_read_ipc(from, &request, sizeof(struct terminal_command)); + if (read != sizeof(struct terminal_command)) { + syslogf("received %u / %u bytes of a command from 0x%2x", read, sizeof(struct terminal_command), from); + continue; + } + //syslogf("received full command from 0x%2x", from); + + switch (request.kind) { + case SET_DIMENSIONS: + set_dimensions(request.as_coords.y, request.as_coords.x); + continue; + union terminal_response rs; + case GET_DIMENSIONS: + rs.as_coords.y = rows; + rs.as_coords.x = cols; + try_send_ipc(from, &rs, sizeof(union terminal_response)); + continue; + case PAINT: + _paint_window(window); + continue; + case CLEAR: + clear(); + cursor_y = 0; + cursor_x = 0; + draw_char(0, 0, true); + continue; + case SET_COLOR: + fg_color = request.as_color.fg; + bg_color = request.as_color.bg; + draw_all(); + continue; + case SET_CURSOR: + draw_char(cursor_y, cursor_x, false); + cursor_y = request.as_coords.y; + cursor_x = request.as_coords.x; + draw_char(cursor_y, cursor_x, true); + continue; + case CURSOR_LEFT: + draw_char(cursor_y, cursor_x, false); + if (cursor_x) + --cursor_x; + else if (cursor_y) { + cursor_x = cols - 1; + --cursor_y; + } + draw_char(cursor_y, cursor_x, true); + continue; + case CURSOR_RIGHT: + draw_char(cursor_y, cursor_x, false); + cursor_right(); + draw_char(cursor_y, cursor_x, true); + continue; + case CURSOR_UP: + if (cursor_y) { + draw_char(cursor_y, cursor_x, false); + --cursor_y; + draw_char(cursor_y, cursor_x, true); + } + continue; + case CURSOR_DOWN: + draw_char(cursor_y, cursor_x, false); + if (cursor_y == rows - 1) + scroll_fw(); + else + ++cursor_y; + draw_char(cursor_y, cursor_x, true); + continue; + case ADD_CHAR: + add_char(request.as_char); + draw_char(cursor_y, cursor_x, true); + continue; + case ADD_SN: + draw_char(cursor_y, cursor_x, false); + get_sn(request.as_uint, from); + add_sz_ww(sz_from_task); + draw_char(cursor_y, cursor_x, true); + continue; + case ADD_SN_NO_WORDWRAP: + draw_char(cursor_y, cursor_x, false); + get_sn(request.as_uint, from); + add_sz_no_ww(sz_from_task); + draw_char(cursor_y, cursor_x, true); + continue; + struct waiting_for_key_record *new_record; + case GET_KEY: + new_record = get_block(sizeof(struct waiting_for_key_record)); + if (last_key_waiting) + last_key_waiting->next = new_record; + else + first_key_waiting = new_record; + last_key_waiting = new_record; + new_record->task = from; + new_record->next = 0; + continue; + default: + add_sz_ww("Bad terminal command received, ignoring.\n"); + continue; + } + } +} \ No newline at end of file diff --git a/src/user/terminal/readline.c b/src/user/terminal/readline.c deleted file mode 100644 index 37ef54b..0000000 --- a/src/user/terminal/readline.c +++ /dev/null @@ -1,104 +0,0 @@ -#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 deleted file mode 100644 index 7961fd5..0000000 --- a/src/user/terminal/terminal.c +++ /dev/null @@ -1,284 +0,0 @@ -#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