diff options
author | Jon Santmyer <jon@jonsantmyer.com> | 2021-11-11 08:31:44 -0500 |
---|---|---|
committer | Jon Santmyer <jon@jonsantmyer.com> | 2021-11-11 08:31:44 -0500 |
commit | a310ca40440e4798eea01107646b92253a3f7881 (patch) | |
tree | 6c0f682cd6aaa141898726cb21765f96942d228a | |
parent | 216e17bebb84483c33b0de40ab05778eef58560a (diff) | |
download | modit-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.h | 53 | ||||
-rw-r--r-- | include/arch_x86/common/syscall.h | 23 | ||||
-rw-r--r-- | include/arch_x86/common/task.h | 2 | ||||
-rw-r--r-- | src/arch_x86/64/task/context.c | 11 | ||||
-rw-r--r-- | src/arch_x86/64/task/message.c | 67 | ||||
-rw-r--r-- | src/arch_x86/64/task/port.c | 191 | ||||
-rw-r--r-- | src/arch_x86/common/syscall/syscall.c | 76 |
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 = ¤t_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 }; |