diff options
author | dzwdz | 2022-05-05 21:41:04 +0200 |
---|---|---|
committer | dzwdz | 2022-05-05 21:41:04 +0200 |
commit | f9bc4ac436dec5f2f1f1db31c4933c80ed40568b (patch) | |
tree | 05124db3cfc86556df603c05543457eb60d20f4e /src | |
parent | dc42353f53df0b5425377330f16e668829d8fd9a (diff) |
kernel: move the COM1 driver to a separate handler
Diffstat (limited to 'src')
-rw-r--r-- | src/kernel/arch/i386/driver/ps2.c | 1 | ||||
-rw-r--r-- | src/kernel/arch/i386/driver/serial.c | 48 | ||||
-rw-r--r-- | src/kernel/arch/i386/driver/serial.h | 4 | ||||
-rw-r--r-- | src/kernel/main.c | 2 | ||||
-rw-r--r-- | src/kernel/proc.c | 28 | ||||
-rw-r--r-- | src/kernel/syscalls.c | 3 | ||||
-rw-r--r-- | src/kernel/vfs/mount.c | 25 | ||||
-rw-r--r-- | src/kernel/vfs/mount.h | 1 | ||||
-rw-r--r-- | src/kernel/vfs/root.c | 42 |
9 files changed, 86 insertions, 68 deletions
diff --git a/src/kernel/arch/i386/driver/ps2.c b/src/kernel/arch/i386/driver/ps2.c index 6ee24e2..666fa76 100644 --- a/src/kernel/arch/i386/driver/ps2.c +++ b/src/kernel/arch/i386/driver/ps2.c @@ -29,6 +29,7 @@ size_t ps2_read(uint8_t *buf, size_t len) { } int vfs_ps2_accept(struct vfs_request *req) { + // when you fix something here go also fix it in the COM1 driver static uint8_t buf[32]; // pretty damn stupid int ret; switch (req->type) { diff --git a/src/kernel/arch/i386/driver/serial.c b/src/kernel/arch/i386/driver/serial.c index 40d4a77..4e274d8 100644 --- a/src/kernel/arch/i386/driver/serial.c +++ b/src/kernel/arch/i386/driver/serial.c @@ -1,6 +1,7 @@ #include <kernel/arch/i386/driver/serial.h> #include <kernel/arch/i386/interrupts/irq.h> #include <kernel/arch/i386/port_io.h> +#include <kernel/mem/virt.h> #include <kernel/panic.h> #include <shared/container/ring.h> #include <shared/mem.h> @@ -12,6 +13,8 @@ static volatile ring_t backlog = {(void*)backlog_buf, BACKLOG_CAPACITY, 0, 0}; static const int COM1 = 0x3f8; +static struct vfs_request *blocked_on = NULL; + static void serial_selftest(void) { char b = 0x69; @@ -43,6 +46,11 @@ bool serial_ready(void) { void serial_irq(void) { ring_put1b((void*)&backlog, port_in8(COM1)); + if (blocked_on) { + vfs_com1_accept(blocked_on); + blocked_on = NULL; + // TODO vfs_backend_tryaccept + } } size_t serial_read(char *buf, size_t len) { @@ -59,3 +67,43 @@ void serial_write(const char *buf, size_t len) { for (size_t i = 0; i < len; i++) serial_putchar(buf[i]); } + + +int vfs_com1_accept(struct vfs_request *req) { + static uint8_t buf[32]; + int ret; + switch (req->type) { + case VFSOP_OPEN: + return vfsreq_finish(req, 0); + case VFSOP_READ: + if (serial_ready()) { + if (req->caller) { + // clamp between 0, sizeof buf + ret = req->output.len; + if (ret > sizeof buf) ret = sizeof buf; + if (ret < 0) ret = 0; + + ret = serial_read(buf, ret); + virt_cpy_to(req->caller->pages, req->output.buf, buf, ret); + } else ret = -1; + return vfsreq_finish(req, ret); + } else { + blocked_on = req; + return -1; + } + case VFSOP_WRITE: + if (req->caller) { + struct virt_iter iter; + virt_iter_new(&iter, req->input.buf, req->input.len, + req->caller->pages, true, false); + while (virt_iter_next(&iter)) + serial_write(iter.frag, iter.frag_len); + ret = iter.prior; + } else ret = -1; + return vfsreq_finish(req, ret); + default: + return vfsreq_finish(req, -1); + } +} + +bool vfs_com1_ready(struct vfs_backend *self) { return blocked_on == NULL; } diff --git a/src/kernel/arch/i386/driver/serial.h b/src/kernel/arch/i386/driver/serial.h index c2b93ce..e7f9b7c 100644 --- a/src/kernel/arch/i386/driver/serial.h +++ b/src/kernel/arch/i386/driver/serial.h @@ -1,4 +1,5 @@ #pragma once +#include <kernel/vfs/request.h> #include <stdbool.h> #include <stddef.h> @@ -9,3 +10,6 @@ void serial_irq(void); size_t serial_read(char *buf, size_t len); void serial_write(const char *buf, size_t len); + +int vfs_com1_accept(struct vfs_request *); +bool vfs_com1_ready(struct vfs_backend *); diff --git a/src/kernel/main.c b/src/kernel/main.c index a0fdd07..5023ea9 100644 --- a/src/kernel/main.c +++ b/src/kernel/main.c @@ -24,6 +24,8 @@ void shutdown(void) { size_t states[PS_LAST] = {0}; for (struct process *p = process_first; p; p = process_next(p)) states[p->state]++; + + kprintf("\n\n\nshutting off\n"); for (size_t i = 0; i < sizeof(states) / sizeof(*states); i++) kprintf("state 0x%x: 0x%x\n", i, states[i]); diff --git a/src/kernel/proc.c b/src/kernel/proc.c index ed317ec..c9e3aef 100644 --- a/src/kernel/proc.c +++ b/src/kernel/proc.c @@ -123,34 +123,18 @@ static _Noreturn void process_switch(struct process *proc) { sysexit(proc->regs); } -/** If there are any processes waiting for IRQs, wait with them. Otherwise, shut down */ -static _Noreturn void process_idle(void) { - // this mess is temporary - - struct process *procs[16]; - size_t len = process_find_multiple(PS_WAITS4IRQ, procs, 16); - - if (len == 0) shutdown(); - - cpu_pause(); - for (size_t i = 0; i < len; i++) { - if (procs[i]->waits4irq.ready()) { - /* if this is entered during the first iteration, it indicates a - * kernel bug. this should be logged. TODO? */ - procs[i]->waits4irq.callback(procs[i]); - } - } - - process_switch_any(); -} - _Noreturn void process_switch_any(void) { if (process_current && process_current->state == PS_RUNNING) process_switch(process_current); struct process *found = process_find(PS_RUNNING); if (found) process_switch(found); - process_idle(); + + if (process_first->state == PS_DEAD || process_first->state == PS_DEADER) + shutdown(); + + cpu_pause(); + process_switch_any(); } struct process *process_next(struct process *p) { diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c index 1ec8ed9..c5e25b7 100644 --- a/src/kernel/syscalls.c +++ b/src/kernel/syscalls.c @@ -113,7 +113,8 @@ int _syscall_mount(handle_t hid, const char __user *path, int len) { // TODO move to kernel/vfs/mount.c mount = kmalloc(sizeof *mount); mount->prev = process_current->mount; - mount->prefix = path_buf; // owned + mount->prefix = path_buf; + mount->prefix_owned = true; mount->prefix_len = len; mount->backend = backend; mount->refs = 1; diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c index 232e702..178cc54 100644 --- a/src/kernel/vfs/mount.c +++ b/src/kernel/vfs/mount.c @@ -4,7 +4,9 @@ #include <kernel/vfs/root.h> #include <shared/mem.h> +// TODO not the place where this should be done #include <kernel/arch/i386/driver/ps2.h> +#include <kernel/arch/i386/driver/serial.h> struct vfs_mount *vfs_mount_seed(void) { struct vfs_mount *mount = kmalloc(sizeof *mount); @@ -19,7 +21,7 @@ struct vfs_mount *vfs_mount_seed(void) { .prefix = NULL, .prefix_len = 0, .backend = backend, - .refs = 1, // never to be freed + .refs = 1, }; // what a mess. @@ -39,7 +41,23 @@ struct vfs_mount *vfs_mount_seed(void) { .refs = 1, }; - return ps2; + // oh god oh fuck + struct vfs_mount *com = kmalloc(sizeof *com); + backend = kmalloc(sizeof *backend); + backend->is_user = false; + backend->potential_handlers = 1; + backend->refcount = 1; + backend->kern.ready = vfs_com1_ready; + backend->kern.accept = vfs_com1_accept; + *com = (struct vfs_mount){ + .prev = ps2, + .prefix = "/com1", + .prefix_len = 5, + .backend = backend, + .refs = 1, + }; + + return com; } struct vfs_mount *vfs_mount_resolve( @@ -71,7 +89,8 @@ void vfs_mount_remref(struct vfs_mount *mnt) { struct vfs_mount *prev = mnt->prev; if (mnt->backend) vfs_backend_refdown(mnt->backend); - kfree(mnt->prefix); + if (mnt->prefix_owned) + kfree(mnt->prefix); kfree(mnt); if (prev) vfs_mount_remref(prev); diff --git a/src/kernel/vfs/mount.h b/src/kernel/vfs/mount.h index 96a2d7b..4aa08d4 100644 --- a/src/kernel/vfs/mount.h +++ b/src/kernel/vfs/mount.h @@ -6,6 +6,7 @@ struct vfs_mount { struct vfs_mount *prev; char *prefix; size_t prefix_len; + bool prefix_owned; struct vfs_backend *backend; size_t refs; /* counts all references, atm from: * - struct vfs_mount diff --git a/src/kernel/vfs/root.c b/src/kernel/vfs/root.c index 0c58d86..c1b16fa 100644 --- a/src/kernel/vfs/root.c +++ b/src/kernel/vfs/root.c @@ -1,6 +1,4 @@ #include <kernel/arch/i386/ata.h> -#include <kernel/arch/i386/driver/ps2.h> -#include <kernel/arch/i386/driver/serial.h> #include <kernel/mem/virt.h> #include <kernel/panic.h> #include <kernel/proc.h> @@ -14,7 +12,6 @@ enum { HANDLE_ROOT, HANDLE_VGA, - HANDLE_COM1, HANDLE_ATA_ROOT, HANDLE_ATA, _SKIP = HANDLE_ATA + 4, @@ -52,25 +49,12 @@ static void wait_callback(struct process *proc) { vfs_root_accept(proc->waits4irq.req); } -static bool wait_setup(struct vfs_request *req, bool *ready, bool (*ready_fn)()) { - if (!ready_fn()) { - *ready = false; - process_transition(req->caller, PS_WAITS4IRQ); - req->caller->waits4irq.req = req; - req->caller->waits4irq.ready = ready_fn; - req->caller->waits4irq.callback = wait_callback; - return true; - } - return false; -} - static int handle(struct vfs_request *req, bool *ready) { assert(req->caller); switch (req->type) { case VFSOP_OPEN: if (exacteq(req, "/")) return HANDLE_ROOT; if (exacteq(req, "/vga")) return HANDLE_VGA; - if (exacteq(req, "/com1")) return HANDLE_COM1; if (exacteq(req, "/ata/")) return HANDLE_ATA_ROOT; if (exacteq(req, "/ata/0")) @@ -104,13 +88,6 @@ static int handle(struct vfs_request *req, bool *ready) { vga + req->offset, req->output.len); return req->output.len; } - case HANDLE_COM1: { - if (wait_setup(req, ready, serial_ready)) return -1; - char buf[16]; - size_t len = serial_read(buf, min(req->output.len, sizeof buf)); - virt_cpy_to(req->caller->pages, req->output.buf, buf, len); - return len; - } case HANDLE_ATA_ROOT: { // TODO offset char list[8] = {}; @@ -147,14 +124,6 @@ static int handle(struct vfs_request *req, bool *ready) { req->input.buf, req->input.len); return req->input.len; } - case HANDLE_COM1: { - struct virt_iter iter; - virt_iter_new(&iter, req->input.buf, req->input.len, - req->caller->pages, true, false); - while (virt_iter_next(&iter)) - serial_write(iter.frag, iter.frag_len); - return iter.prior; - } default: return -1; } @@ -167,17 +136,6 @@ static int handle(struct vfs_request *req, bool *ready) { int vfs_root_accept(struct vfs_request *req) { if (req->caller) { - /* this introduces a difference between the root vfs and emulated ones: - * - * the root vfs has to immediately discard requests from dead processes. - * so, if 16 processes queue up for an IRQ, and the middle 14 quit, only - * 2 IRQs will be processed - * - * but if they do that in an emulated root vfs, all 16 IRQs will be processed - * - * to fix this, i need to make it so callerless requests can also wait - * for IRQs. - */ bool ready = true; int ret = handle(req, &ready); if (ready) { |