diff options
author | Marvin Borner | 2021-04-17 22:59:57 +0200 |
---|---|---|
committer | Marvin Borner | 2021-04-17 22:59:57 +0200 |
commit | cdf029471736f43776452930b7195a06ab143654 (patch) | |
tree | f8ab7dee26c589ff3666194b814d9457482ec02c | |
parent | 89b5b9acf6037fc1a87f9e85c64831187a47ba94 (diff) |
Added I/O bus implementation for efficient IPC
This was a nice coding session. See ya tomorrow!
-rw-r--r-- | apps/init/init.c | 1 | ||||
-rw-r--r-- | apps/wm/wm.c | 10 | ||||
-rw-r--r-- | kernel/Makefile | 1 | ||||
-rw-r--r-- | kernel/drivers/fb.c | 2 | ||||
-rw-r--r-- | kernel/features/bus.c | 310 | ||||
-rw-r--r-- | kernel/features/io.c | 28 | ||||
-rw-r--r-- | kernel/features/proc.c | 22 | ||||
-rw-r--r-- | kernel/inc/bus.h | 8 | ||||
-rw-r--r-- | kernel/inc/proc.h | 2 | ||||
-rw-r--r-- | libs/libc/crypto.c | 13 | ||||
-rw-r--r-- | libs/libc/inc/crypto.h | 4 | ||||
-rw-r--r-- | libs/libc/inc/sys.h | 7 | ||||
-rw-r--r-- | libs/libc/sys.c | 2 |
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); } |