summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
authordzwdz2023-09-09 16:54:13 +0200
committerdzwdz2023-09-09 16:54:13 +0200
commit4516acc2814de7e1420109a9469600a5607eb984 (patch)
treef528afa2d2158c1d06ee203926e8c06251642868 /src/kernel
parentb7e5252ab4955039ca548d7f8216bfc432a3bd62 (diff)
kernel: build /kdev/ on the fly
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/arch/amd64/driver/fsroot.c103
-rw-r--r--src/kernel/arch/amd64/driver/pata.c13
-rw-r--r--src/kernel/arch/amd64/driver/ps2.c10
-rw-r--r--src/kernel/arch/amd64/driver/video.c6
-rw-r--r--src/kernel/vfs/mount.c5
5 files changed, 87 insertions, 50 deletions
diff --git a/src/kernel/arch/amd64/driver/fsroot.c b/src/kernel/arch/amd64/driver/fsroot.c
index ed7e88c..0eef12f 100644
--- a/src/kernel/arch/amd64/driver/fsroot.c
+++ b/src/kernel/arch/amd64/driver/fsroot.c
@@ -2,59 +2,90 @@
#include <camellia/fsutil.h>
#include <kernel/arch/amd64/driver/driver.h>
#include <kernel/arch/amd64/driver/util.h>
+#include <kernel/malloc.h>
#include <kernel/panic.h>
#include <kernel/proc.h>
#include <kernel/util.h>
+#include <kernel/vfs/mount.h>
#include <kernel/vfs/request.h>
#include <shared/mem.h>
-static long handle(VfsReq *req) {
- // TODO document directory read format
- // TODO don't hardcode
- static const char base[] = "kdev/";
- static const char dir[] =
- "com1\0"
- "ps2/\0"
- "ata/\0"
- "eth\0"
- "video/";
- const char *id;
- int len;
+enum {
+ Hbase,
+ Hkdev,
+};
+
+static int
+get_kdev(char *lst)
+{
+ int len = 0;
+ for (VfsMount *m = vfs_mount_seed(); m; m = m->prev) {
+ if (m->prefix_len == 0) {
+ continue; /* that's us */
+ }
+ assert(m->prefix_len > 6);
+ assert(memcmp(m->prefix, "/kdev/", 6) == 0);
+ len += m->prefix_len - 6 + 1;
+ if (lst) {
+ memcpy(lst, m->prefix + 6, m->prefix_len - 6);
+ lst += m->prefix_len - 6;
+ *lst++ = '\0';
+ }
+ }
+ return len;
+}
+
+static long
+handle(VfsReq *req)
+{
+ static char *kdev = NULL;
+ static int kdev_len = 0;
+ const char *lst = NULL;
+ int len = 0;
if (!req->caller) return -1;
if (req->type != VFSOP_OPEN) {
- /* otherwise, uninitialized, to cause compiler warnings if used */
- /* this operates under the assumption that base and dir never change
- * but even if they do, that will just result in a crash. */
- id = (void *__force)req->id;
- if (id == base) {
- len = sizeof base;
- } else if (id == dir) {
- len = sizeof dir;
- } else {
- kprintf("%p %p %p\n", base, dir, id);
+ switch ((uintptr_t __force)req->id) {
+ case Hbase:
+ lst = "kdev/";
+ len = strlen(lst) + 1;
+ break;
+ case Hkdev:
+ if (!kdev) {
+ kdev_len = get_kdev(NULL);
+ kdev = kmalloc(kdev_len);
+ get_kdev(kdev);
+ }
+ lst = kdev;
+ len = kdev_len;
+ break;
+ default:
assert(false);
}
}
switch (req->type) {
- case VFSOP_OPEN:
- if (reqpathcmp(req, "/")) return (long)base;
- if (reqpathcmp(req, "/kdev/")) return (long)dir;
- return -ENOENT;
-
- case VFSOP_READ:
- return req_readcopy(req, id, len);
- // TODO getsize for the other kernel provided directories
- case VFSOP_GETSIZE:
- return len;
- default:
- return -ENOSYS;
+ case VFSOP_OPEN:
+ if (reqpathcmp(req, "/")) return Hbase;
+ if (reqpathcmp(req, "/kdev/")) return Hkdev;
+ return -ENOENT;
+ case VFSOP_READ:
+ return req_readcopy(req, lst, len);
+ case VFSOP_GETSIZE:
+ return len;
+ default:
+ return -ENOSYS;
}
}
-static void accept(VfsReq *req) {
+static void
+accept(VfsReq *req)
+{
vfsreq_finish_short(req, handle(req));
}
-void vfs_root_init(void) { vfs_root_register("", accept); }
+void
+vfs_root_init(void)
+{
+ vfs_root_register("", accept);
+}
diff --git a/src/kernel/arch/amd64/driver/pata.c b/src/kernel/arch/amd64/driver/pata.c
index b0058f8..da8b541 100644
--- a/src/kernel/arch/amd64/driver/pata.c
+++ b/src/kernel/arch/amd64/driver/pata.c
@@ -13,7 +13,7 @@ static const int root_id = 100;
static void accept(VfsReq *req);
void pata_init(void) {
ata_init();
- vfs_root_register("/kdev/ata", accept);
+ vfs_root_register("/kdev/ata/", accept);
}
static void accept(VfsReq *req) {
@@ -23,11 +23,11 @@ static void accept(VfsReq *req) {
size_t len;
switch (req->type) {
case VFSOP_OPEN:
- if (reqpathcmp(req, "/")) ret = root_id;
- else if (reqpathcmp(req, "/0")) ret = 0;
- else if (reqpathcmp(req, "/1")) ret = 1;
- else if (reqpathcmp(req, "/2")) ret = 2;
- else if (reqpathcmp(req, "/3")) ret = 3;
+ if (reqpathcmp(req, "")) ret = root_id;
+ else if (reqpathcmp(req, "0")) ret = 0;
+ else if (reqpathcmp(req, "1")) ret = 1;
+ else if (reqpathcmp(req, "2")) ret = 2;
+ else if (reqpathcmp(req, "3")) ret = 3;
else ret = -ENOENT;
// TODO don't allow opening nonexistent drives
vfsreq_finish_short(req, ret);
@@ -70,6 +70,7 @@ static void accept(VfsReq *req) {
case VFSOP_GETSIZE:
if (id == root_id) {
+ // TODO getsize for all kernel provided directories
panic_unimplemented();
}
vfsreq_finish_short(req, ata_size(id));
diff --git a/src/kernel/arch/amd64/driver/ps2.c b/src/kernel/arch/amd64/driver/ps2.c
index e314477..f2a98a2 100644
--- a/src/kernel/arch/amd64/driver/ps2.c
+++ b/src/kernel/arch/amd64/driver/ps2.c
@@ -58,7 +58,7 @@ void ps2_init(void) {
irq_fn[IRQ_PS2KB] = ps2_irq;
irq_fn[IRQ_PS2MOUSE] = ps2_irq;
- vfs_root_register("/kdev/ps2", accept);
+ vfs_root_register("/kdev/ps2/", accept);
}
static void ps2_irq(void) {
@@ -86,10 +86,10 @@ static void accept(VfsReq *req) {
int ret;
switch (req->type) {
case VFSOP_OPEN:
- if (reqpathcmp(req, "/")) ret = H_ROOT;
- else if (reqpathcmp(req, "/kb")) ret = H_KB;
- else if (reqpathcmp(req, "/mouse")) ret = H_MOUSE;
- else ret = -ENOENT;
+ if (reqpathcmp(req, "")) ret = H_ROOT;
+ else if (reqpathcmp(req, "kb")) ret = H_KB;
+ else if (reqpathcmp(req, "mouse")) ret = H_MOUSE;
+ else ret = -ENOENT;
vfsreq_finish_short(req, ret);
break;
case VFSOP_READ:
diff --git a/src/kernel/arch/amd64/driver/video.c b/src/kernel/arch/amd64/driver/video.c
index 5a7fc8f..390e8dd 100644
--- a/src/kernel/arch/amd64/driver/video.c
+++ b/src/kernel/arch/amd64/driver/video.c
@@ -21,9 +21,9 @@ static int handle(VfsReq *req) {
switch (req->type) {
case VFSOP_OPEN:
if (!req->input.kern) panic_invalid_state();
- if (req->input.len == 1) {
+ if (req->input.len == 0) {
return H_ROOT;
- } else if (req->input.len == namelen + 1 && !memcmp(req->input.buf_kern + 1, namebuf, namelen)) {
+ } else if (req->input.len == namelen && !memcmp(req->input.buf_kern, namebuf, namelen)) {
return H_FB;
} else {
return -1;
@@ -65,5 +65,5 @@ void video_init(GfxInfo fb_) {
fb = fb_;
snprintf(namebuf, sizeof namebuf, "%ux%ux%u", fb.width, fb.height, fb.bpp);
namelen = strlen(namebuf);
- vfs_root_register("/kdev/video", accept);
+ vfs_root_register("/kdev/video/", accept);
}
diff --git a/src/kernel/vfs/mount.c b/src/kernel/vfs/mount.c
index b4f5b0f..c153c69 100644
--- a/src/kernel/vfs/mount.c
+++ b/src/kernel/vfs/mount.c
@@ -45,6 +45,11 @@ VfsMount *vfs_mount_resolve(
break;
if (path[top->prefix_len] == '/')
break;
+
+ /* Also valid if prefix ends with '/'. Can only happen with kernel-
+ * provided mounts. */
+ if (top->prefix_len != 0 && path[top->prefix_len-1] == '/')
+ break;
}
return top;
}