summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/elf.c10
-rw-r--r--src/kernel/elf.h2
-rw-r--r--src/kernel/ide.c2
-rw-r--r--src/kernel/idt.c200
-rw-r--r--src/kernel/isrs.asm44
-rw-r--r--src/kernel/kbd.c410
-rw-r--r--src/kernel/kbd.h5
-rw-r--r--src/kernel/log.c103
-rw-r--r--src/kernel/log.h15
-rw-r--r--src/kernel/main.c118
-rw-r--r--src/kernel/panic.c18
-rw-r--r--src/kernel/pmap.h2
-rw-r--r--src/kernel/serial.c6
-rw-r--r--src/kernel/task.c203
-rw-r--r--src/kernel/task.h34
-rw-r--r--src/kernel/util.c93
-rw-r--r--src/kernel/util.h8
-rw-r--r--src/kernel/vga.c52
-rw-r--r--src/kernel/vga.h12
-rw-r--r--src/kernel/window.c253
-rw-r--r--src/kernel/window.h23
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