diff options
author | Benji Dial <benji6283@gmail.com> | 2021-01-24 12:00:11 -0500 |
---|---|---|
committer | Benji Dial <benji6283@gmail.com> | 2021-01-24 12:00:11 -0500 |
commit | bce944d1498eaa3b6940ee234c863b3548a66b37 (patch) | |
tree | ea40c087ab4f0f236aee8d158cf68550f5209f72 /src/kernel | |
parent | ca731aa747214919df7b3dfe3478dbe787ce5b68 (diff) | |
download | portland-os-bce944d1498eaa3b6940ee234c863b3548a66b37.tar.gz |
graphics!
Diffstat (limited to 'src/kernel')
-rw-r--r-- | src/kernel/elf.c | 10 | ||||
-rw-r--r-- | src/kernel/elf.h | 2 | ||||
-rw-r--r-- | src/kernel/ide.c | 2 | ||||
-rw-r--r-- | src/kernel/idt.c | 200 | ||||
-rw-r--r-- | src/kernel/isrs.asm | 44 | ||||
-rw-r--r-- | src/kernel/kbd.c | 410 | ||||
-rw-r--r-- | src/kernel/kbd.h | 5 | ||||
-rw-r--r-- | src/kernel/log.c | 103 | ||||
-rw-r--r-- | src/kernel/log.h | 15 | ||||
-rw-r--r-- | src/kernel/main.c | 118 | ||||
-rw-r--r-- | src/kernel/panic.c | 18 | ||||
-rw-r--r-- | src/kernel/pmap.h | 2 | ||||
-rw-r--r-- | src/kernel/serial.c | 6 | ||||
-rw-r--r-- | src/kernel/task.c | 203 | ||||
-rw-r--r-- | src/kernel/task.h | 34 | ||||
-rw-r--r-- | src/kernel/util.c | 93 | ||||
-rw-r--r-- | src/kernel/util.h | 8 | ||||
-rw-r--r-- | src/kernel/vga.c | 52 | ||||
-rw-r--r-- | src/kernel/vga.h | 12 | ||||
-rw-r--r-- | src/kernel/window.c | 253 | ||||
-rw-r--r-- | src/kernel/window.h | 23 |
21 files changed, 963 insertions, 650 deletions
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 <stdint.h> #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 <stdint.h> + +#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 <stdint.h> +#include <keypack.h> + 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 <stdarg.h> +#include <stdbool.h> + #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 <stdarg.h> + +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 <stdint.h> +#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 <stdint.h> + #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 <stdint.h> #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 <stdbool.h> -#include <stdint.h> - -#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 <stdint.h> - -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 <stdint.h> + +#include <winact.h> + +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 |