summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kernel/arch/i386/driver/ps2.c1
-rw-r--r--src/kernel/arch/i386/driver/serial.c48
-rw-r--r--src/kernel/arch/i386/driver/serial.h4
-rw-r--r--src/kernel/main.c2
-rw-r--r--src/kernel/proc.c28
-rw-r--r--src/kernel/syscalls.c3
-rw-r--r--src/kernel/vfs/mount.c25
-rw-r--r--src/kernel/vfs/mount.h1
-rw-r--r--src/kernel/vfs/root.c42
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) {