aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarvin Borner2021-04-17 22:59:57 +0200
committerMarvin Borner2021-04-17 22:59:57 +0200
commitcdf029471736f43776452930b7195a06ab143654 (patch)
treef8ab7dee26c589ff3666194b814d9457482ec02c
parent89b5b9acf6037fc1a87f9e85c64831187a47ba94 (diff)
Added I/O bus implementation for efficient IPC
This was a nice coding session. See ya tomorrow!
-rw-r--r--apps/init/init.c1
-rw-r--r--apps/wm/wm.c10
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/drivers/fb.c2
-rw-r--r--kernel/features/bus.c310
-rw-r--r--kernel/features/io.c28
-rw-r--r--kernel/features/proc.c22
-rw-r--r--kernel/inc/bus.h8
-rw-r--r--kernel/inc/proc.h2
-rw-r--r--libs/libc/crypto.c13
-rw-r--r--libs/libc/inc/crypto.h4
-rw-r--r--libs/libc/inc/sys.h7
-rw-r--r--libs/libc/sys.c2
13 files changed, 371 insertions, 39 deletions
diff --git a/apps/init/init.c b/apps/init/init.c
index 6e06dbe..44cf461 100644
--- a/apps/init/init.c
+++ b/apps/init/init.c
@@ -10,7 +10,6 @@ int main(int argc, char **argv)
UNUSED(argv);
assert(exec("wm", NULL) == EOK);
- /* assert(exec("chess", NULL) == EOK); */
return 0;
}
diff --git a/apps/wm/wm.c b/apps/wm/wm.c
index 23b5879..8f3b21f 100644
--- a/apps/wm/wm.c
+++ b/apps/wm/wm.c
@@ -494,7 +494,7 @@ int main(int argc, char **argv)
atexit(handle_exit);
- assert(io_control(IO_FRAMEBUFFER, 0, &screen) == EOK);
+ assert(io_control(IO_FRAMEBUFFER, IOCTL_FB_GET, &screen) == EOK);
log("WM loaded: %dx%d\n", screen.width, screen.height);
wm_client = (struct client){ .pid = getpid() };
bypp = (screen.bpp >> 3);
@@ -513,15 +513,17 @@ int main(int argc, char **argv)
WF_NO_DRAG | WF_NO_FOCUS | WF_NO_RESIZE);
/* gfx_write(&direct->ctx, vec2(0, 0), FONT_32, COLOR_FG, "Loading Melvix..."); */
- gfx_load_wallpaper(&wallpaper->ctx, "/res/wall.png");
+ /* gfx_load_wallpaper(&wallpaper->ctx, "/res/wall.png"); */
memset(cursor->ctx.fb, 0, cursor->ctx.bytes);
gfx_load_wallpaper(&cursor->ctx, "/res/cursor.png");
window_redraw(wallpaper);
+ assert(io_control(IO_BUS, IOCTL_BUS_REGISTER, "wm") == EOK);
+
u8 msg[1024] = { 0 };
struct event_keyboard event_keyboard = { 0 };
struct event_mouse event_mouse = { 0 };
- u32 listeners[] = { IO_KEYBOARD, IO_MOUSE, 0 };
+ enum io_type listeners[] = { IO_KEYBOARD, IO_MOUSE, IO_BUS, 0 };
while (1) {
res poll_ret = 0;
@@ -538,7 +540,7 @@ int main(int argc, char **argv)
continue;
}
} else if (poll_ret == IO_BUS) {
- if (msg_receive(msg, sizeof(msg)) > 0) {
+ if (io_read(IO_BUS, msg, 0, sizeof(msg)) > 0) {
handle_message(msg);
continue;
}
diff --git a/kernel/Makefile b/kernel/Makefile
index 03ad960..2b75415 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -16,6 +16,7 @@ COBJS = main.o \
features/mm.o \
features/fs.o \
features/io.o \
+ features/bus.o \
features/load.o \
features/proc.o \
features/proc_asm.o \
diff --git a/kernel/drivers/fb.c b/kernel/drivers/fb.c
index dcccf72..fce0c9e 100644
--- a/kernel/drivers/fb.c
+++ b/kernel/drivers/fb.c
@@ -30,7 +30,7 @@ static res fb_ioctl(u32 request, void *arg1, void *arg2, void *arg3)
UNUSED(arg3);
switch (request) {
- case 0: {
+ case IOCTL_FB_GET: {
if (!info)
return -ENOENT;
diff --git a/kernel/features/bus.c b/kernel/features/bus.c
new file mode 100644
index 0000000..f8a561c
--- /dev/null
+++ b/kernel/features/bus.c
@@ -0,0 +1,310 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#include <assert.h>
+#include <bus.h>
+#include <cpu.h>
+#include <crypto.h>
+#include <def.h>
+#include <errno.h>
+#include <io.h>
+#include <list.h>
+#include <mem.h>
+#include <mm.h>
+#include <stack.h>
+#include <str.h>
+
+// TODO: Consider different hashing method (possible duplicates in crc32)
+
+// Bus conns are always between *two* clients!
+struct bus_conn {
+ u32 bus; // Bus name hash
+ u32 conn;
+ struct stack *in; // Queue of bus owner
+ struct stack *out; // Queue of other client
+};
+
+struct bus_message {
+ void *data;
+ u32 conn;
+ u32 size;
+};
+
+struct bus {
+ u32 pid; // Owner
+ char name[128];
+ u32 hash;
+};
+
+PROTECTED struct list *bus_list = NULL;
+PROTECTED struct list *bus_conns = NULL;
+static u32 conn_cnt = 1; // 0 is reserved
+
+static struct bus *bus_find_bus(u32 hash)
+{
+ struct node *iterator = bus_list->head;
+ while (iterator) {
+ struct bus *bus = iterator->data;
+ if (bus->hash == hash)
+ return bus;
+
+ iterator = iterator->next;
+ }
+
+ return NULL;
+}
+
+static struct bus_conn *bus_find_conn(u32 conn)
+{
+ struct node *iterator = bus_conns->head;
+ while (iterator) {
+ struct bus_conn *bus_conn = iterator->data;
+ if (bus_conn->conn == conn)
+ return bus_conn;
+
+ iterator = iterator->next;
+ }
+
+ return NULL;
+}
+
+static struct bus *bus_find_owner(u32 pid)
+{
+ struct node *iterator = bus_list->head;
+ while (iterator) {
+ struct bus *bus = iterator->data;
+ if (bus->pid == pid)
+ return bus;
+
+ iterator = iterator->next;
+ }
+
+ return NULL;
+}
+
+static void bus_add_conn(u32 hash, u32 conn)
+{
+ struct bus_conn *bus_conn = zalloc(sizeof(*bus_conn));
+ bus_conn->bus = hash;
+ bus_conn->conn = conn;
+ bus_conn->in = stack_new();
+ bus_conn->out = stack_new();
+ list_add(bus_conns, bus_conn);
+}
+
+static res bus_register(const char *name)
+{
+ if (!memory_readable(name))
+ return -EFAULT;
+
+ u32 len = strlen_user(name);
+ if (len >= 128)
+ return -E2BIG;
+
+ u32 hash = crc32_user(0, name, len);
+ if (bus_find_bus(hash))
+ return -EBUSY;
+
+ struct bus *bus = zalloc(sizeof(*bus));
+ strlcpy_user(bus->name, name, sizeof(bus->name));
+ bus->pid = proc_current()->pid;
+ bus->hash = hash;
+ list_add(bus_list, bus);
+
+ return EOK;
+}
+
+static res bus_connect(const char *bus, u32 *conn)
+{
+ if (!memory_readable(bus) || !memory_writable(conn))
+ return -EFAULT;
+
+ u32 len = strlen_user(bus);
+ if (len >= 128)
+ return -E2BIG;
+
+ u32 hash = crc32_user(0, bus, len);
+ if (!bus_find_bus(hash))
+ return -ENOENT;
+
+ u32 conn_id = conn_cnt++;
+ bus_add_conn(hash, conn_id);
+ proc_current()->bus_conn = conn_id;
+
+ stac();
+ *conn = conn_id;
+ clac();
+
+ return EOK;
+}
+
+static res bus_send(u32 conn, void *buf, u32 count)
+{
+ if (!count)
+ return EOK;
+
+ if (!memory_readable(buf))
+ return -EFAULT;
+
+ struct bus_conn *bus_conn = bus_find_conn(conn);
+ if (!bus_conn)
+ return -ENOENT;
+
+ struct bus *bus = bus_find_bus(bus_conn->bus);
+ if (!bus)
+ return -ENOENT;
+
+ void *data = zalloc(count);
+ memcpy_user(data, buf, count);
+ struct bus_message *msg = zalloc(sizeof(*msg));
+ msg->data = data;
+ msg->conn = conn;
+ msg->size = count;
+
+ if (bus->pid == proc_current()->pid)
+ stack_push_bot(bus_conn->in, msg);
+ else
+ stack_push_bot(bus_conn->out, msg);
+
+ return count;
+}
+
+static res bus_conn_receive(struct bus_conn *bus_conn, void *buf, u32 offset, u32 count)
+{
+ struct bus *bus = bus_find_bus(bus_conn->bus);
+ if (!bus)
+ return -ENOENT;
+
+ struct bus_message *msg = NULL;
+ if (bus->pid == proc_current()->pid)
+ msg = stack_pop(bus_conn->out);
+ else
+ msg = stack_pop(bus_conn->out);
+
+ if (!msg)
+ return -EIO;
+
+ memcpy_user(buf, (u8 *)msg->data + offset, MIN(count, msg->size));
+ free(msg->data);
+ free(msg);
+ return MIN(count, msg->size);
+}
+
+static res bus_receive(void *buf, u32 offset, u32 count)
+{
+ if (!count)
+ return EOK;
+
+ if (!memory_readable(buf))
+ return -EFAULT;
+
+ struct bus *bus_owner = bus_find_owner(proc_current()->pid);
+ struct bus_conn *bus_conn = bus_find_conn(proc_current()->bus_conn);
+ if (!bus_owner && !bus_conn)
+ return -ENOENT;
+
+ // TODO: Better round-robin
+
+ if (bus_owner) {
+ struct node *iterator = bus_conns->head;
+ while (iterator) {
+ struct bus_conn *sub_bus = iterator->data;
+ if (sub_bus->bus == bus_owner->hash)
+ return bus_conn_receive(sub_bus, buf, offset, count);
+
+ iterator = iterator->next;
+ }
+ }
+
+ if (bus_conn)
+ return bus_conn_receive(bus_conn, buf, offset, count);
+
+ return -EAGAIN;
+}
+
+/**
+ * I/O integrations
+ */
+
+static res bus_control(u32 request, void *arg1, void *arg2, void *arg3)
+{
+ UNUSED(arg3);
+
+ switch (request) {
+ case IOCTL_BUS_CONNECT: {
+ return bus_connect(arg1, arg2);
+ }
+ case IOCTL_BUS_REGISTER: {
+ return bus_register(arg1);
+ }
+ default: {
+ return -EINVAL;
+ }
+ }
+}
+
+static res bus_write(void *buf, u32 offset, u32 count)
+{
+ if (offset)
+ return -EINVAL;
+
+ return bus_send(proc_current()->bus_conn, buf, count);
+}
+
+static res bus_read(void *buf, u32 offset, u32 count)
+{
+ return bus_receive(buf, offset, count);
+}
+
+static res bus_conn_ready(struct bus_conn *bus_conn)
+{
+ struct bus *bus = bus_find_bus(bus_conn->bus);
+ if (!bus)
+ return -ENOENT;
+
+ u8 ready = 0;
+ if (bus->pid == proc_current()->pid)
+ ready = !stack_empty(bus_conn->out);
+ else
+ ready = !stack_empty(bus_conn->out);
+
+ return ready ? EOK : -EAGAIN;
+}
+
+static res bus_ready(void)
+{
+ struct bus *bus_owner = bus_find_owner(proc_current()->pid);
+ struct bus_conn *bus_conn = bus_find_conn(proc_current()->bus_conn);
+ if (!bus_owner && !bus_conn)
+ return -ENOENT;
+
+ // TODO: Better round-robin
+
+ if (bus_owner) {
+ struct node *iterator = bus_conns->head;
+ while (iterator) {
+ struct bus_conn *sub_bus = iterator->data;
+ if (sub_bus->bus == bus_owner->hash)
+ return bus_conn_ready(sub_bus);
+
+ iterator = iterator->next;
+ }
+ }
+
+ if (bus_conn)
+ return bus_conn_ready(bus_conn);
+
+ return -EAGAIN;
+}
+
+CLEAR void bus_install(void)
+{
+ bus_list = list_new();
+ bus_conns = list_new();
+
+ struct io_dev *dev = zalloc(sizeof(*dev));
+ dev->control = bus_control;
+ dev->read = bus_read;
+ dev->ready = bus_ready;
+ dev->write = bus_write;
+ io_add(IO_BUS, dev);
+}
diff --git a/kernel/features/io.c b/kernel/features/io.c
index d0cca07..c48eb62 100644
--- a/kernel/features/io.c
+++ b/kernel/features/io.c
@@ -1,6 +1,7 @@
// MIT License, Copyright (c) 2021 Marvin Borner
#include <assert.h>
+#include <bus.h>
#include <cpu.h>
#include <def.h>
#include <fb.h>
@@ -83,16 +84,23 @@ res io_poll(u32 *devs)
io_remove_group(group);
group--;
return -ENOENT;
- } else if (dev->ready && dev->ready() == EOK) {
- io_remove_group(group);
- group--;
- return io;
- } else {
- struct io_listener *listener = zalloc(sizeof(*listener));
- listener->group = group;
- listener->proc = proc_current();
- list_add(io_listeners[io], listener);
}
+
+ if (dev->ready) {
+ res ready = dev->ready();
+ if (ready == EOK) {
+ io_remove_group(group);
+ group--;
+ return io;
+ } else if (ready != -EAGAIN) {
+ return ready;
+ }
+ }
+
+ struct io_listener *listener = zalloc(sizeof(*listener));
+ listener->group = group;
+ listener->proc = proc_current();
+ list_add(io_listeners[io], listener);
}
proc_state(proc_current(), PROC_BLOCKED);
@@ -161,7 +169,6 @@ void io_block(enum io_type io, struct proc *proc)
void io_unblock(enum io_type io)
{
- printf("%d\n", group_id);
assert(io_type_valid(io));
struct node *iterator = io_listeners[io]->head;
while (iterator) {
@@ -194,4 +201,5 @@ CLEAR void io_install(struct boot_info *boot)
timer_install();
fb_install(boot->vid);
+ bus_install();
}
diff --git a/kernel/features/proc.c b/kernel/features/proc.c
index c972f1b..cada97d 100644
--- a/kernel/features/proc.c
+++ b/kernel/features/proc.c
@@ -288,15 +288,7 @@ static res procfs_write(const char *path, void *buf, u32 offset, u32 count, stru
clac();
path++;
- if (!memcmp_user(path, "msg", 4)) {
- void *msg_data = malloc(count);
- memcpy_user(msg_data, buf, count);
- struct procfs_message *msg = malloc(sizeof(*msg));
- msg->data = msg_data;
- msg->size = count;
- stack_push_bot(p->messages, msg); // TODO: Use offset
- return count;
- } else if (!memcmp_user(path, "io/", 3)) {
+ if (!memcmp_user(path, "io/", 3)) {
path += 3;
enum stream_defaults id = procfs_stream(path);
if (id == STREAM_UNKNOWN)
@@ -346,18 +338,6 @@ static res procfs_read(const char *path, void *buf, u32 offset, u32 count, struc
const char *status = p->state == PROC_RUNNING ? "running" : "sleeping";
memcpy_user(buf, status + offset, count);
return count;
- } else if (!memcmp_user(path, "msg", 4)) {
- if (stack_empty(p->messages)) {
- return -EIO; // This shouldn't happen
- } else {
- struct procfs_message *msg = stack_pop(p->messages);
- if (!msg)
- return -EIO;
- memcpy_user(buf, msg->data + offset, MIN(count, msg->size));
- free(msg->data);
- free(msg);
- return MIN(count, msg->size);
- }
} else if (!memcmp_user(path, "io/", 3)) {
path += 3;
enum stream_defaults id = procfs_stream(path);
diff --git a/kernel/inc/bus.h b/kernel/inc/bus.h
new file mode 100644
index 0000000..271df34
--- /dev/null
+++ b/kernel/inc/bus.h
@@ -0,0 +1,8 @@
+// MIT License, Copyright (c) 2021 Marvin Borner
+
+#ifndef BUS_H
+#define BUS_H
+
+void bus_install(void);
+
+#endif
diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h
index 1d5d064..1e3f037 100644
--- a/kernel/inc/proc.h
+++ b/kernel/inc/proc.h
@@ -48,6 +48,8 @@ struct proc {
struct stack *messages;
struct list *memory;
+ u32 bus_conn;
+
struct {
u32 user;
u32 kernel;
diff --git a/libs/libc/crypto.c b/libs/libc/crypto.c
index 310931d..c2d51ba 100644
--- a/libs/libc/crypto.c
+++ b/libs/libc/crypto.c
@@ -164,3 +164,16 @@ u32 crc32(u32 crc, const void *buf, u32 size)
return crc ^ ~0UL;
}
+
+#ifdef KERNEL
+
+#include <cpu.h>
+u32 crc32_user(u32 crc, const void *buf, u32 size)
+{
+ stac();
+ u32 ret = crc32(crc, buf, size);
+ clac();
+ return ret;
+}
+
+#endif
diff --git a/libs/libc/inc/crypto.h b/libs/libc/inc/crypto.h
index 16cdf86..b672c50 100644
--- a/libs/libc/inc/crypto.h
+++ b/libs/libc/inc/crypto.h
@@ -8,4 +8,8 @@
void md5(const void *initial_msg, u32 initial_len, u8 digest[16]) NONNULL;
u32 crc32(u32 crc, const void *buf, u32 size) NONNULL;
+#ifdef KERNEL
+u32 crc32_user(u32 crc, const void *buf, u32 size) NONNULL;
+#endif
+
#endif
diff --git a/libs/libc/inc/sys.h b/libs/libc/inc/sys.h
index 461db2e..72a8029 100644
--- a/libs/libc/inc/sys.h
+++ b/libs/libc/inc/sys.h
@@ -42,6 +42,11 @@ enum io_type {
IO_MAX,
};
+// I/O control declarations
+#define IOCTL_FB_GET 0
+#define IOCTL_BUS_CONNECT 0
+#define IOCTL_BUS_REGISTER 1
+
struct event_keyboard {
u32 magic;
u32 scancode;
@@ -77,7 +82,7 @@ res write(const char *path, const void *buf, u32 offset, u32 count) NONNULL;
res stat(const char *path, struct stat *buf) NONNULL;
res exec(const char *path, ...) ATTR((nonnull(1))) SENTINEL;
-res io_poll(u32 *devs) NONNULL;
+res io_poll(enum io_type *devs) NONNULL;
res io_read(enum io_type io, void *buf, u32 offset, u32 count) NONNULL;
res io_write(enum io_type io, void *buf, u32 offset, u32 count) NONNULL;
res io_control(enum io_type io, ...);
diff --git a/libs/libc/sys.c b/libs/libc/sys.c
index 3161d72..b0e6e93 100644
--- a/libs/libc/sys.c
+++ b/libs/libc/sys.c
@@ -128,7 +128,7 @@ res exec(const char *path, ...)
return sys5(SYS_EXEC, (int)path, args[0], args[1], args[2], args[3]);
}
-res io_poll(u32 *devs)
+res io_poll(enum io_type *devs)
{
return sys1(SYS_IOPOLL, (int)devs);
}