summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2021-11-11 08:31:44 -0500
committerJon Santmyer <jon@jonsantmyer.com>2021-11-11 08:31:44 -0500
commita310ca40440e4798eea01107646b92253a3f7881 (patch)
tree6c0f682cd6aaa141898726cb21765f96942d228a
parent216e17bebb84483c33b0de40ab05778eef58560a (diff)
downloadmodit-kernel-a310ca40440e4798eea01107646b92253a3f7881.tar.gz
modit-kernel-a310ca40440e4798eea01107646b92253a3f7881.tar.bz2
modit-kernel-a310ca40440e4798eea01107646b92253a3f7881.zip
add message and port icc
-rw-r--r--include/arch_x86/common/ipc.h53
-rw-r--r--include/arch_x86/common/syscall.h23
-rw-r--r--include/arch_x86/common/task.h2
-rw-r--r--src/arch_x86/64/task/context.c11
-rw-r--r--src/arch_x86/64/task/message.c67
-rw-r--r--src/arch_x86/64/task/port.c191
-rw-r--r--src/arch_x86/common/syscall/syscall.c76
7 files changed, 416 insertions, 7 deletions
diff --git a/include/arch_x86/common/ipc.h b/include/arch_x86/common/ipc.h
new file mode 100644
index 0000000..f451e18
--- /dev/null
+++ b/include/arch_x86/common/ipc.h
@@ -0,0 +1,53 @@
+#ifndef MODIT_KERNEL_IPC_H
+#define MODIT_KERNEL_IPC_H 1
+
+#include <stddef.h>
+#include <stdint.h>
+#include "mutex.h"
+#include "list.h"
+
+#define IPC_PORT_DATA_MAX 4096
+
+#define IPC_MESSAGE_MAX 16
+#define IPC_MESSAGE_DATA_MAX 0x10000
+
+typedef intmax_t portid_t;
+
+struct port
+{
+ struct mutex lock;
+ size_t parties[2];
+ uint16_t datalen;
+ uint8_t data[IPC_PORT_DATA_MAX];
+};
+
+struct message
+{
+ struct sllist listhead;
+ size_t sender;
+ size_t datalen;
+ uint8_t *data;
+};
+
+struct mailbox
+{
+ struct mutex lock;
+ size_t messagec;
+ struct message *messages_tail;
+};
+
+
+//Opens a port for bidirectional communication between contexts a and b
+//Only one port can exist between a and b
+//If port already exists, returns the existing port
+portid_t port_open(size_t a, size_t b);
+int port_close(portid_t id);
+int port_clear(portid_t id);
+//Reads with NULL buffer returns data size
+int port_read(portid_t id, uint8_t *buffer, size_t n);
+int port_write(portid_t id, uint8_t *buffer, size_t n);
+
+int message_send(size_t tgt, uint8_t *data, size_t len);
+int message_recv(uint8_t *buffer, size_t *sender);
+
+#endif
diff --git a/include/arch_x86/common/syscall.h b/include/arch_x86/common/syscall.h
index d9bb47d..280a55f 100644
--- a/include/arch_x86/common/syscall.h
+++ b/include/arch_x86/common/syscall.h
@@ -2,6 +2,7 @@
#define MODIT_KERNEL_SYSCALL_H 1
#include <stdint.h>
+#include <stddef.h>
#include <stdbool.h>
struct syscall_frame
@@ -25,6 +26,15 @@ enum {
SYSCALL_CID,
SYSCALL_TICK,
+
+ SYSCALL_PORT_OPEN,
+ SYSCALL_PORT_CLOSE,
+ SYSCALL_PORT_CLEAR,
+ SYSCALL_PORT_READ,
+ SYSCALL_PORT_WRITE,
+
+ SYSCALL_MESSAGE_SEND,
+ SYSCALL_MESSAGE_RECV,
SYSCALL_MAX
};
extern syscall_t syscalls[SYSCALL_MAX];
@@ -76,4 +86,17 @@ struct syscall_tick_data {
int ms;
};
+struct syscall_port_data {
+ intmax_t id;
+ intmax_t tgt;
+ uint8_t *buffer;
+ size_t len;
+};
+
+struct syscall_message_data {
+ intmax_t tgt;
+ uint8_t *buffer;
+ size_t len;
+};
+
#endif
diff --git a/include/arch_x86/common/task.h b/include/arch_x86/common/task.h
index 0d87211..eac5cc2 100644
--- a/include/arch_x86/common/task.h
+++ b/include/arch_x86/common/task.h
@@ -10,6 +10,7 @@
#define MODIT_KERNEL_STAST 0xFFFFFF0000000000
#include "list.h"
+#include "ipc.h"
#include <stdbool.h>
#include <stdint.h>
@@ -25,6 +26,7 @@ struct execution_context
uintptr_t bp;
uintptr_t privs;
+ struct mailbox mailbox;
};
extern struct execution_context *execution_contexts;
diff --git a/src/arch_x86/64/task/context.c b/src/arch_x86/64/task/context.c
index 65c5949..d7d57b8 100644
--- a/src/arch_x86/64/task/context.c
+++ b/src/arch_x86/64/task/context.c
@@ -37,6 +37,17 @@ excontext_set_timer(size_t ms) {
}
struct execution_context *
+excontext_find(size_t id)
+{
+ sll_foreach(struct execution_context, execution_contexts) {
+ if(node->id == id) {
+ return node;
+ }
+ }
+ return NULL;
+}
+
+struct execution_context *
excontext_append(uintptr_t cr3, uintptr_t ip, uintptr_t sp, uintptr_t bp)
{
struct execution_context *ctx = kmalloc(sizeof(struct execution_context), "ex context");
diff --git a/src/arch_x86/64/task/message.c b/src/arch_x86/64/task/message.c
new file mode 100644
index 0000000..64649ae
--- /dev/null
+++ b/src/arch_x86/64/task/message.c
@@ -0,0 +1,67 @@
+#include "ipc.h"
+#include "modit.h"
+#include "task.h"
+#include "mutex.h"
+#include "stdio.h"
+
+int
+message_send(size_t tgt, uint8_t *data, size_t len)
+{
+ struct execution_context *ctx = excontext_find(tgt);
+ if(ctx == NULL) return -1;
+
+ struct mailbox *mbx = &ctx->mailbox;
+
+ //Lock until mailbox has space
+ while(mbx->messagec > IPC_MESSAGE_MAX);
+ mbx->messagec++;
+
+ mutex_lock(&mbx->lock);
+ struct message *msg = kmalloc(sizeof(struct message), "message");
+ uint8_t *msgdat = kmalloc(len, "message data");
+
+ memset(msg, 0, sizeof(struct message));
+ memcpy(msgdat, data, len);
+
+ msg->sender = current_excontext->id;
+ msg->datalen = len;
+ msg->data = msgdat;
+
+ if(mbx->messages_tail == NULL) {
+ mbx->messages_tail = msg;
+ }else{
+ sll_appbeg(mbx->messages_tail, msg);
+ }
+
+ mutex_unlock(&mbx->lock);
+ return 0;
+}
+
+int
+message_recv(uint8_t *buffer, size_t *sender)
+{
+ struct mailbox *mbx = &current_excontext->mailbox;
+
+ //Lock until mailbox has messages
+ while(mbx->messagec == 0);
+ mbx->messagec--;
+
+ mutex_lock(&mbx->lock);
+
+ struct message *msg = mbx->messages_tail;
+ if(buffer == NULL) {
+ mutex_unlock(&mbx->lock);
+ mbx->messagec++;
+ return msg->datalen;
+ }
+
+ mbx->messages_tail = (struct message*)(msg->listhead.next);
+ memcpy(buffer, msg->data, msg->datalen);
+ *sender = msg->sender;
+
+ kfree(msg->data);
+ kfree(msg);
+
+ mutex_unlock(&mbx->lock);
+ return 0;
+}
diff --git a/src/arch_x86/64/task/port.c b/src/arch_x86/64/task/port.c
new file mode 100644
index 0000000..bda3658
--- /dev/null
+++ b/src/arch_x86/64/task/port.c
@@ -0,0 +1,191 @@
+#include "ipc.h"
+#include "modit.h"
+#include "task.h"
+#include "heap.h"
+#include "stdlib.h"
+#include "stdio.h"
+
+static intmax_t portc = 0;
+static struct port *ports;
+MUTEX(ipc_ports)
+
+struct port *
+port_findopen(portid_t *id)
+{
+ //Check through the port list for empty entries
+ LOCK(ipc_ports)
+ for(portid_t i = 0; i < portc; i++) {
+ if(ports[i].parties[0] == 0) {
+ *id = i;
+ UNLOCK(ipc_ports)
+ return &ports[i];
+ }
+ }
+
+ //Make space for new port
+ struct port *tmp = kmalloc(sizeof(struct port) * (portc + 1), "ports");
+ memcpy(tmp, ports, sizeof(struct port) * (portc));
+ kfree(ports);
+ ports = tmp;
+
+ *id = portc++;
+ UNLOCK(ipc_ports)
+ return &ports[*id];
+}
+
+struct port *
+port_get(portid_t id)
+{
+ if(portc <= id) return NULL;
+ struct port *r;
+ LOCK(ipc_ports)
+ r = &ports[id];
+ UNLOCK(ipc_ports)
+ return r;
+}
+
+portid_t
+port_open(size_t a, size_t b)
+{
+ //Find if exists
+ LOCK(ipc_ports)
+ for(intmax_t i = 0; i < portc; i++) {
+ if((ports[i].parties[0] == a && ports[i].parties[1] == b) ||
+ (ports[i].parties[1] == a && ports[i].parties[0] == b)) {
+ UNLOCK(ipc_ports)
+ return i;
+ }
+ }
+ UNLOCK(ipc_ports)
+
+ portid_t id = 0;
+ struct port *port = port_findopen(&id);
+
+ if(port == NULL) return -1;
+
+ mutex_lock(&port->lock);
+ port->parties[0] = a;
+ port->parties[1] = b;
+ port->datalen = 0;
+ mutex_unlock(&port->lock);
+
+ return id;
+}
+
+int
+port_close(portid_t id)
+{
+ struct port *port = port_get(id);
+ if(port == NULL) return -1;
+ LOCK(ipc_ports)
+ mutex_lock(&port->lock);
+
+ //Make sure the closer owns the port
+ if(port->parties[0] != current_excontext->id &&
+ port->parties[1] != current_excontext->id) {
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return -2;
+ }
+
+ //Clear ownership from the port
+ port->parties[0] = 0;
+ port->parties[1] = 0;
+
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return 0;
+}
+
+int port_clear(portid_t id)
+{
+ struct port *port = port_get(id);
+ if(port == NULL) return -1;
+ LOCK(ipc_ports)
+ mutex_lock(&port->lock);
+
+ //Make sure the closer owns the port
+ if(port->parties[0] != current_excontext->id &&
+ port->parties[1] != current_excontext->id) {
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return -2;
+ }
+
+ port->datalen = 0;
+
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return 0;
+}
+
+int
+port_read(portid_t id, uint8_t *buffer, size_t n)
+{
+ struct port *port = port_get(id);
+ if(port == NULL) return -1;
+ LOCK(ipc_ports)
+ mutex_lock(&port->lock);
+
+ //Make sure the closer owns the port
+ if(port->parties[0] != current_excontext->id &&
+ port->parties[1] != current_excontext->id) {
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return -2;
+ }
+
+ if(buffer == NULL) {
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return port->datalen;
+ }
+ if(n > port->datalen) n = port->datalen;
+
+ memcpy(buffer, port->data, n);
+
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return n;
+}
+
+int
+port_write(portid_t id, uint8_t *buffer, size_t n)
+{
+ struct port *port = port_get(id);
+ if(port == NULL) return -1;
+ LOCK(ipc_ports)
+ mutex_lock(&port->lock);
+
+ //Make sure the closer owns the port
+ if(port->parties[0] != current_excontext->id &&
+ port->parties[1] != current_excontext->id) {
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return -2;
+ }
+
+ if(buffer == NULL) {
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return 0;
+ }
+ if(n > IPC_PORT_DATA_MAX) n = IPC_PORT_DATA_MAX;
+
+ memcpy(port->data, buffer, n);
+ if(port->datalen < n) port->datalen = n;
+
+ mutex_unlock(&port->lock);
+ UNLOCK(ipc_ports)
+ return n;
+}
+
+MODULE static void
+ipc_port_constructor(void)
+{
+ ports = kmalloc(sizeof(struct port), "ports");
+ memset(ports, 0, sizeof(struct port));
+
+ portc = 1;
+ printk(KERNEL_OK, "Setup port IPC\n");
+}
diff --git a/src/arch_x86/common/syscall/syscall.c b/src/arch_x86/common/syscall/syscall.c
index 0b90f1b..45fccf7 100644
--- a/src/arch_x86/common/syscall/syscall.c
+++ b/src/arch_x86/common/syscall/syscall.c
@@ -3,6 +3,7 @@
#include "task.h"
#include "vmm.h"
#include "pmm.h"
+#include "ipc.h"
#define POINTER_BOUND_CHECK(ptr) \
if((uintptr_t)ptr > MODIT_USER_MAX) return -SYSCALL_ERR_OOB; \
@@ -79,12 +80,7 @@ syscall_switch(struct syscall_switch_data *data)
{
struct execution_context *tgt = NULL;
POINTER_CHECK(data)
- sll_foreach(struct execution_context, execution_contexts) {
- if(node->id == data->id) {
- tgt = node;
- break;
- }
- }
+ tgt = excontext_find(data->id);
if(!tgt) return -SYSCALL_ERR_NOTFOUND;
excontext_switch(tgt);
@@ -107,6 +103,65 @@ syscall_tick(struct syscall_tick_data *data)
return 0;
}
+int
+syscall_port_open(struct syscall_port_data *data)
+{
+ POINTER_CHECK(data)
+ return port_open(current_excontext->id, data->tgt);
+}
+
+int
+syscall_port_close(struct syscall_port_data *data)
+{
+ POINTER_CHECK(data)
+ return port_close(data->id);
+}
+
+int
+syscall_port_clear(struct syscall_port_data *data)
+{
+ POINTER_CHECK(data)
+ return port_clear(data->id);
+}
+
+int
+syscall_port_read(struct syscall_port_data *data)
+{
+ POINTER_CHECK(data)
+ if(data->buffer != NULL) {
+ POINTER_CHECK(data->buffer)
+ }
+ return port_read(data->id, data->buffer, data->len);
+}
+
+int
+syscall_port_write(struct syscall_port_data *data)
+{
+ POINTER_CHECK(data)
+ if(data->buffer != NULL) {
+ POINTER_CHECK(data->buffer)
+ }
+ return port_write(data->id, data->buffer, data->len);
+}
+
+int
+syscall_message_send(struct syscall_message_data *data)
+{
+ POINTER_CHECK(data)
+ POINTER_CHECK(data->buffer)
+ return message_send(data->tgt, data->buffer, data->len);
+}
+
+int
+syscall_message_recv(struct syscall_message_data *data)
+{
+ POINTER_CHECK(data)
+ if(data->buffer != NULL) {
+ POINTER_CHECK(data->buffer)
+ }
+ return message_recv(data->buffer, &data->tgt);
+}
+
syscall_t syscalls[SYSCALL_MAX] =
{
syscall_print,
@@ -117,5 +172,12 @@ syscall_t syscalls[SYSCALL_MAX] =
syscall_fork,
syscall_switch,
syscall_cid,
- syscall_tick
+ syscall_tick,
+ syscall_port_open,
+ syscall_port_close,
+ syscall_port_clear,
+ syscall_port_read,
+ syscall_port_write,
+ syscall_message_send,
+ syscall_message_recv
};