From 41a0679039434b049e416c98494316347b6c2b24 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Thu, 5 Sep 2024 16:35:19 -0400 Subject: [PATCH 01/51] ipc: structure for unix sockets --- src/include/kernel/socket.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/include/kernel/socket.h diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h new file mode 100644 index 00000000..d471c84d --- /dev/null +++ b/src/include/kernel/socket.h @@ -0,0 +1,36 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +#pragma once + +#include +#include + +/* socket family/domain - only Unix sockets will be implemented in the kernel */ +#define AF_UNIX 1 +#define AF_LOCAL AF_UNIX + +/* socket type - these will all be the same for the local Unix sockets */ +/* the kernel will ensure packets are sent and received in the same order */ +#define SOCK_STREAM 1 // stream-oriented +#define SOCK_DGRAM 2 // datagram-oriented +#define SOCK_SEQPACKET 3 // connection-oriented + +typedef uint32_t sa_family_t; +typedef size_t socklen_t; + +/* generic socket */ +struct sockaddr { + sa_family_t sa_family; + char sa_data[]; +} + +/* Unix domain socket */ +struct sockaddr_un { + sa_family_t sun_family; // AF_UNIX + char sun_path[512]; // filename +} \ No newline at end of file From fcba94d9841b32037ecd54689d47823dcdc2eae3 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Thu, 5 Sep 2024 22:28:41 -0400 Subject: [PATCH 02/51] io: start of per-process I/O descriptors --- src/include/kernel/io.h | 27 +++++++++++++++++++++++++++ src/include/kernel/sched.h | 5 +++++ src/include/kernel/socket.h | 18 +++++++++++++----- 3 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/include/kernel/io.h diff --git a/src/include/kernel/io.h b/src/include/kernel/io.h new file mode 100644 index 00000000..618770f3 --- /dev/null +++ b/src/include/kernel/io.h @@ -0,0 +1,27 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +/* Abstractions for file systems and sockets */ + +#include +#include + +// these are special and reserved descriptors +#define IO_STDIN 0 +#define IO_STDOUT 1 +#define IO_STDERR 2 + +#define IO_FILE 3 +#define IO_SOCKET 4 + +// TODO: decide whether to implement named pipes as files or an independent type + +typedef struct { + bool valid; + int type; + void *data; // file or socket-specific data +} IODescriptor; diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 19fd1a4f..81e14fe1 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -12,6 +12,7 @@ #include #include #include +#include // ideal number of context switches per second // still not sure of how to decide on this value so it'll probably change @@ -19,6 +20,8 @@ #define MAX_PID 99999 +#define MAX_IO_DESCRIPTORS 1024 // max files/sockets open per process + #define THREAD_QUEUED 0 #define THREAD_RUNNING 1 #define THREAD_BLOCKED 2 // waiting for I/O @@ -56,6 +59,8 @@ typedef struct Process { char *env; // environmental variables char *command; // command line with arguments + IODescriptor io[MAX_IO_DESCRIPTORS]; + size_t threadCount; size_t childrenCount; diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index d471c84d..e074b53f 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -14,23 +14,31 @@ #define AF_UNIX 1 #define AF_LOCAL AF_UNIX -/* socket type - these will all be the same for the local Unix sockets */ +/* socket type - these will be ignored for local Unix sockets */ /* the kernel will ensure packets are sent and received in the same order */ #define SOCK_STREAM 1 // stream-oriented #define SOCK_DGRAM 2 // datagram-oriented #define SOCK_SEQPACKET 3 // connection-oriented -typedef uint32_t sa_family_t; +typedef uint16_t sa_family_t; typedef size_t socklen_t; /* generic socket */ struct sockaddr { sa_family_t sa_family; - char sa_data[]; -} + char sa_data[512]; +}; /* Unix domain socket */ struct sockaddr_un { sa_family_t sun_family; // AF_UNIX char sun_path[512]; // filename -} \ No newline at end of file +}; + +/* socket-specific I/O descriptor (see io.h) */ +typedef struct { + struct sockaddr socket; + int backlog; + int inboundCount, outboundCount; + void **inbound, **outbound; +} SocketDescriptor; From 16445be580c84a41d5af7ee3570b950ca08ad27a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Thu, 5 Sep 2024 22:58:33 -0400 Subject: [PATCH 03/51] errno: system error numbers --- src/include/errno.h | 88 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 src/include/errno.h diff --git a/src/include/errno.h b/src/include/errno.h new file mode 100644 index 00000000..c04ee66c --- /dev/null +++ b/src/include/errno.h @@ -0,0 +1,88 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +#pragma once + +/* System Error Numbers */ + +#define E2BIG 1 // too many args +#define EACCES 2 // access denied +#define EADDRINUSE 3 // address in use +#define EADDRNOTAVAIL 4 // address not available +#define EAFNOSUPPORT 5 // address family not supported +#define EAGAIN 6 // resource busy, try again +#define EALREADY 7 // connection already in progress +#define EBADF 8 // bad file descriptor +#define EBADMSG 9 // bad message +#define EBUSY 10 // resource busy +#define ECANCELED 11 // canceled +#define ECHILD 12 // no child processes +#define ECONNABORTED 13 // connection aborted +#define ECONNREFUSED 14 // connection refused +#define ECONNRESET 15 // connection reset +#define EDEADLK 16 // deadlock +#define EDESTADDRREQ 17 // destination address required +#define EDOM 18 // function argument not in domain +#define EDQUOT 19 // reserved +#define EEXIST 20 // file exists +#define EFAULT 21 // bad address +#define EFBIG 22 // file too big +#define EHOSTUNREACH 23 // host unreachable +#define EIDRM 24 // identifier removed +#define EILSEQ 25 // illegal byte sequence +#define EINPROGRESS 26 // operation in progress +#define EINTR 27 // interrupted function +#define EINVAL 28 // invalid argument +#define EIO 29 // I/O error +#define EISCONN 30 // socket already connected +#define EISDIR 31 // directory +#define ELOOP 32 // looping symlinks +#define EMFILE 33 // file descriptor too big +#define EMLINK 34 // too many links +#define EMSGSIZE 35 // message too large +#define EMULTIHOP 36 // reserved +#define ENAMETOOLONG 37 // file name too long +#define ENETDOWN 38 // network is down +#define ENETRESET 39 // connection aborted by network +#define ENETUNREACH 40 // network unreachable +#define ENFILE 41 // too many files open +#define ENOBUFS 42 // no buffers available +#define ENODEV 43 // no such device +#define ENOENT 44 // no such file/directory +#define ENOEXEC 45 // executable file error +#define ENOLCK 46 // no locks available +#define ENOLINK 47 // reserved +#define ENOMEM 48 // ran out of memory +#define ENOMSG 49 // no message of desired type +#define ENOPROTOOPT 50 // protocol not implemented +#define ENOSPC 51 // ran out of storage +#define ENOSYS 52 // function not supported +#define ENOCONN 53 // socket not connected +#define ENOTDIR 54 // not a directory nor symlink to directory +#define ENOTEMPTY 55 // directory not empty +#define ENOTRECOVERABLE 56 // unrecoverable error +#define ENOTSOCK 57 // not a socket +#define ENOTSUP 58 // operation not supported +#define EOPNOTSUPP ENOTSUP +#define ENOTTY 59 // inappropriate I/O +#define ENXIO 60 // no such device or address +#define EOVERFLOW 61 // value larger than data type +#define EOWNERDEAD 62 // previous owner died +#define EPERM 63 // operation not permitted +#define EPIPE 64 // broken pipe +#define EPROTO 65 // protocol error +#define EPROTONOSUPPORT 66 // protocol not supported +#define EPROTOTYPE 67 // wrong protocol type +#define ERANGE 68 // result too large +#define EROFS 69 // read-only file system +#define ESPIPE 70 // invalid seek +#define ESRCH 71 // no such process +#define ESTALE 72 // reserved +#define ETIMEDOUT 73 // connection timeout +#define ETXTBSY 74 // text file busy +#define EWOULDBLOCK 75 // blocking operation +#define EXDEV 76 // cross-device link From f7124214c1c32fd2a5393a3ea1834ee90d62cea1 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Thu, 5 Sep 2024 22:59:18 -0400 Subject: [PATCH 04/51] ipc: prototypes for socket syscalls --- src/include/kernel/socket.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index e074b53f..ea24e9b6 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -9,6 +9,7 @@ #include #include +#include /* socket family/domain - only Unix sockets will be implemented in the kernel */ #define AF_UNIX 1 @@ -42,3 +43,12 @@ typedef struct { int inboundCount, outboundCount; void **inbound, **outbound; } SocketDescriptor; + +/* socket system calls */ +int socket(Thread *, int, int, int); +int connect(Thread *, int, const struct sockaddr *, socklen_t); +int bind(Thread *, int, const struct sockaddr *, socklen_t); +int listen(Thread *, int, int); +int accept(Thread *, int, struct sockaddr *, socklen_t *); +ssize_t recv(Thread *, int, void *, size_t, int); +ssize_t send(Thread *, int, const void *, size_t, int); From 82200da422efede6fc6e44263f0264ded623fc0f Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 08:29:21 -0400 Subject: [PATCH 05/51] types: added ssize_t to posix types --- src/include/kernel/socket.h | 1 + src/include/sys/types.h | 1 + 2 files changed, 2 insertions(+) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index ea24e9b6..31f25d23 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -10,6 +10,7 @@ #include #include #include +#include /* socket family/domain - only Unix sockets will be implemented in the kernel */ #define AF_UNIX 1 diff --git a/src/include/sys/types.h b/src/include/sys/types.h index f88335a2..7d86bc4d 100644 --- a/src/include/sys/types.h +++ b/src/include/sys/types.h @@ -22,3 +22,4 @@ typedef uint64_t off_t; typedef uint64_t time_t; typedef uint16_t blksize_t; typedef uint64_t blkcnt_t; +typedef int64_t ssize_t; From 4d3e431346f4406f66f83d250371250f75e2dee8 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 08:29:37 -0400 Subject: [PATCH 06/51] io: prevent multiple includes --- src/include/kernel/io.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/kernel/io.h b/src/include/kernel/io.h index 618770f3..770ccc2b 100644 --- a/src/include/kernel/io.h +++ b/src/include/kernel/io.h @@ -7,6 +7,8 @@ /* Abstractions for file systems and sockets */ +#pragma once + #include #include From cdf4d1356838c075ea3151eaf4398cc60e8d3954 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 09:27:25 -0400 Subject: [PATCH 07/51] sched: stdin, stdout, and stderr descriptors for new processes --- src/include/kernel/sched.h | 1 + src/sched/sched.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 81e14fe1..655866a0 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -60,6 +60,7 @@ typedef struct Process { char *command; // command line with arguments IODescriptor io[MAX_IO_DESCRIPTORS]; + int iodCount; size_t threadCount; size_t childrenCount; diff --git a/src/sched/sched.c b/src/sched/sched.c index 9e6b9d8f..7d2e5fb9 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -155,6 +155,14 @@ pid_t kthreadCreate(void *(*entry)(void *), void *arg) { p->childrenCount = 0; p->children = NULL; + p->iodCount = 3; // stdin, stdout, stderr + p->io[IO_STDIN].type = IO_STDIN; + p->io[IO_STDIN].valid = true; + p->io[IO_STDOUT].type = IO_STDOUT; + p->io[IO_STDOUT].valid = true; + p->io[IO_STDERR].type = IO_STDERR; + p->io[IO_STDERR].valid = true; + p->threads = calloc(1, sizeof(Thread *)); if(!p->threads) { KERROR("failed to allocate memory for kernel thread\n"); @@ -430,6 +438,14 @@ pid_t processCreate() { process->user = 0; // TODO process->group = 0; // TODO + process->iodCount = 3; // stdin, stdout, stderr + process->io[IO_STDIN].type = IO_STDIN; + process->io[IO_STDIN].valid = true; + process->io[IO_STDOUT].type = IO_STDOUT; + process->io[IO_STDOUT].valid = true; + process->io[IO_STDERR].type = IO_STDERR; + process->io[IO_STDERR].valid = true; + // env and command line will be taken care of by fork() or exec() process->threadCount = 0; From 156cedf6df4b9e72bd031f35649b62ebe453b00d Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 09:56:25 -0400 Subject: [PATCH 08/51] sched-io: moved max I/O descriptors to io.h --- src/include/kernel/io.h | 12 +++++++++--- src/include/kernel/sched.h | 4 +--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/include/kernel/io.h b/src/include/kernel/io.h index 770ccc2b..aef63e46 100644 --- a/src/include/kernel/io.h +++ b/src/include/kernel/io.h @@ -11,19 +11,25 @@ #include #include +#include + +#define MAX_IO_DESCRIPTORS 1024 // max files/sockets open per process // these are special and reserved descriptors #define IO_STDIN 0 #define IO_STDOUT 1 #define IO_STDERR 2 -#define IO_FILE 3 -#define IO_SOCKET 4 +#define IO_WAITING 3 // only used during setup +#define IO_FILE 4 +#define IO_SOCKET 5 // TODO: decide whether to implement named pipes as files or an independent type -typedef struct { +typedef struct IODescriptor { bool valid; int type; void *data; // file or socket-specific data } IODescriptor; + +int openIO(void *p, void **iod); diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 655866a0..26b243f2 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -20,8 +20,6 @@ #define MAX_PID 99999 -#define MAX_IO_DESCRIPTORS 1024 // max files/sockets open per process - #define THREAD_QUEUED 0 #define THREAD_RUNNING 1 #define THREAD_BLOCKED 2 // waiting for I/O @@ -59,7 +57,7 @@ typedef struct Process { char *env; // environmental variables char *command; // command line with arguments - IODescriptor io[MAX_IO_DESCRIPTORS]; + struct IODescriptor io[MAX_IO_DESCRIPTORS]; int iodCount; size_t threadCount; From 7de83bb1cb16330638f611f34991880e28f6055a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 09:56:37 -0400 Subject: [PATCH 09/51] io: allocate I/O descriptors for process --- src/io.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/io.c diff --git a/src/io.c b/src/io.c new file mode 100644 index 00000000..c10fbb91 --- /dev/null +++ b/src/io.c @@ -0,0 +1,36 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +/* Abstractions for file systems and sockets */ + +#include +#include +#include +#include + +/* openIO(): opens an I/O descriptor in the current process + * params: p - process to open descriptor in + * params: iod - destination to store pointer to I/O descriptor structure + * returns: I/O descriptor, negative error code on fail + */ + +int openIO(void *pv, void **iodv) { + Process *p = (Process *)pv; + IODescriptor *iod = (IODescriptor *)iodv; + + if(p->iodCount >= MAX_IO_DESCRIPTORS) return -ESRCH; + + /* randomly allocate descriptors instead of sequential numbering */ + int desc; + do { + desc = rand() % MAX_IO_DESCRIPTORS; + } while(p->io[desc].valid); + + p->io[desc].valid = true; + p->io[desc].type = IO_WAITING; + return desc; +} From 9825872f4a00896d581a79e1586122c007ba1383 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 10:04:30 -0400 Subject: [PATCH 10/51] io: close I/O descriptors --- src/include/kernel/io.h | 3 ++- src/io.c | 24 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/include/kernel/io.h b/src/include/kernel/io.h index aef63e46..3cd14ee8 100644 --- a/src/include/kernel/io.h +++ b/src/include/kernel/io.h @@ -32,4 +32,5 @@ typedef struct IODescriptor { void *data; // file or socket-specific data } IODescriptor; -int openIO(void *p, void **iod); +int openIO(void *, void **); +void closeIO(void *, void *); diff --git a/src/io.c b/src/io.c index c10fbb91..5c522a72 100644 --- a/src/io.c +++ b/src/io.c @@ -12,7 +12,7 @@ #include #include -/* openIO(): opens an I/O descriptor in the current process +/* openIO(): opens an I/O descriptor in a process * params: p - process to open descriptor in * params: iod - destination to store pointer to I/O descriptor structure * returns: I/O descriptor, negative error code on fail @@ -32,5 +32,27 @@ int openIO(void *pv, void **iodv) { p->io[desc].valid = true; p->io[desc].type = IO_WAITING; + p->io[desc].data = NULL; + + p->iodCount++; return desc; } + +/* closeIO(): closes an I/O descriptor in a process + * params: pv - process to close descriptor in + * params: iodv - descriptor to close + * returns: nothing + */ + +void closeIO(void *pv, void *iodv) { + Process *p = (Process *)pv; + IODescriptor *iod = (IODescriptor *) iodv; + + if(iod->valid) { + iod->valid = false; + if(iod->data) free(iod->data); + iod->data = NULL; + + p->iodCount--; + } +} From 349cef56144fd8ffc8eabc0d75b5d9b382561a5a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 10:07:55 -0400 Subject: [PATCH 11/51] ipc: socket creation with socket() --- src/include/kernel/socket.h | 4 +-- src/ipc/sockinit.c | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/ipc/sockinit.c diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 31f25d23..20a8b45f 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -39,8 +39,8 @@ struct sockaddr_un { /* socket-specific I/O descriptor (see io.h) */ typedef struct { - struct sockaddr socket; - int backlog; + struct sockaddr address; + int type, protocol, backlog; int inboundCount, outboundCount; void **inbound, **outbound; } SocketDescriptor; diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c new file mode 100644 index 00000000..3c5936ed --- /dev/null +++ b/src/ipc/sockinit.c @@ -0,0 +1,52 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +/* Socket Initialization Functions */ +/* socket(), bind(), and close() for sockets are implemented here */ + +/* I tried my best to follow The Base Specification Issue 8 */ + +#include +#include +#include +#include +#include + +/* socket(): opens a communication socket + * params: t - calling thread, NULL for kernel threads + * params: domain - socket domain/family + * params: type - type of socket (connection, datagram, etc) + * params: protocol - protocol implementing "type" on "domain", zero for default + * returns: positive socket descriptor on success, negative error code on fail + */ + +int socket(Thread *t, int domain, int type, int protocol) { + Process *p; + if(t) p = getProcess(t->pid); + else p = getProcess(getPid()); + + if(!p) return -ESRCH; + if(p->iodCount == MAX_IO_DESCRIPTORS) return -EMFILE; + + IODescriptor *iod = NULL; // open I/O descriptor + int sd = openIO(p, (void **) &iod); + if(sd < 0 || !iod) return sd; + + iod->type = IO_SOCKET; + iod->data = calloc(1, sizeof(SocketDescriptor)); + if(!iod->data) { + closeIO(p, iod); + } + + // set up the socket family for now + SocketDescriptor *sock = (SocketDescriptor *)iod->data; + sock->address.sa_family = domain; + sock->type = type; + sock->protocol = protocol; + + return sd; +} From 1891baacce35943dd1aead4f99ca84579bbf4622 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 15:34:09 -0400 Subject: [PATCH 12/51] x86_64: fix in releaseLock() --- src/platform/x86_64/lock.asm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/x86_64/lock.asm b/src/platform/x86_64/lock.asm index 99aa31ce..64a57fdc 100644 --- a/src/platform/x86_64/lock.asm +++ b/src/platform/x86_64/lock.asm @@ -64,6 +64,6 @@ acquireLockBlocking: global releaseLock align 16 releaseLock: - btr word[rdi], 0 + lock btr word[rdi], 0 xor rax, rax ret From c53991a596f907bca72edc4b59caf679038fdc5d Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 15:49:24 -0400 Subject: [PATCH 13/51] ipc: socket initialization and limits --- src/include/kernel/socket.h | 5 +++++ src/ipc/sockinit.c | 22 ++++++++++++++++++++++ src/main.c | 9 ++++++++- 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 20a8b45f..729debd7 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -12,6 +12,9 @@ #include #include +/* system-wide limit */ +#define MAX_SOCKETS (1 << 20) // little over a million + /* socket family/domain - only Unix sockets will be implemented in the kernel */ #define AF_UNIX 1 #define AF_LOCAL AF_UNIX @@ -45,6 +48,8 @@ typedef struct { void **inbound, **outbound; } SocketDescriptor; +void socketInit(); + /* socket system calls */ int socket(Thread *, int, int, int); int connect(Thread *, int, const struct sockaddr *, socklen_t); diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index 3c5936ed..1178b0b6 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -12,10 +12,32 @@ #include #include +#include #include #include #include +/* array of system-wide open sockets */ +static SocketDescriptor *sockets; +static int socketCount; + +/* socketInit(): initializes the socket subsystem + * params: none + * returns: nothing + */ + +void socketInit() { + sockets = calloc(sizeof(SocketDescriptor *), MAX_SOCKETS); + if(!sockets) { + KERROR("failed to allocate memory for socket subsystem\n"); + while(1); + } + + socketCount = 0; + + KDEBUG("max %d sockets, %d per process\n", MAX_SOCKETS, MAX_IO_DESCRIPTORS); +} + /* socket(): opens a communication socket * params: t - calling thread, NULL for kernel threads * params: domain - socket domain/family diff --git a/src/main.c b/src/main.c index 940f8bcd..bd5ffbd1 100644 --- a/src/main.c +++ b/src/main.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -50,15 +51,21 @@ void *kernelThread(void *args) { } setLumenPID(pid); - idleThread(args); + return idleThread(args); } // the true kernel entry point is called after platform-specific initialization // platform-specific code is in platform/[PLATFORM]/main.c int main(int argc, char **argv) { + /* the platform-specific main() function must initialize some basic form of + * output for debugging, physical and virtual memory, and multiprocessing; the + * boot process will continue here in a more platform-independent fashion */ + + socketInit(); // sockets schedInit(); // scheduler + // number of kernel threads = number of CPU cores kthreadCreate(&kernelThread, NULL); for(int i = 1; i < platformCountCPU(); i++) { From 3f0bcba9bbd96f66ebb8debad97a8a33d194efe8 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 15:53:28 -0400 Subject: [PATCH 14/51] ipc: protect socket list with spinlock --- src/ipc/sockinit.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index 1178b0b6..39bcaf2e 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -12,12 +12,14 @@ #include #include +#include #include #include #include #include /* array of system-wide open sockets */ +static lock_t lock = LOCK_INITIAL; static SocketDescriptor *sockets; static int socketCount; @@ -54,6 +56,8 @@ int socket(Thread *t, int domain, int type, int protocol) { if(!p) return -ESRCH; if(p->iodCount == MAX_IO_DESCRIPTORS) return -EMFILE; + acquireLockBlocking(&lock); + IODescriptor *iod = NULL; // open I/O descriptor int sd = openIO(p, (void **) &iod); if(sd < 0 || !iod) return sd; @@ -61,6 +65,7 @@ int socket(Thread *t, int domain, int type, int protocol) { iod->type = IO_SOCKET; iod->data = calloc(1, sizeof(SocketDescriptor)); if(!iod->data) { + releaseLock(&lock); closeIO(p, iod); } @@ -70,5 +75,9 @@ int socket(Thread *t, int domain, int type, int protocol) { sock->type = type; sock->protocol = protocol; + sockets[socketCount] = sock; + socketCount++; + + releaseLock(&lock); return sd; } From c366c54aeb60a5e41aa76c2a4eefb07b316577fa Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 16:03:17 -0400 Subject: [PATCH 15/51] ipc: implemented socket bind() --- src/ipc/sockinit.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index 39bcaf2e..75445bbd 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -20,7 +21,7 @@ /* array of system-wide open sockets */ static lock_t lock = LOCK_INITIAL; -static SocketDescriptor *sockets; +static SocketDescriptor **sockets; static int socketCount; /* socketInit(): initializes the socket subsystem @@ -81,3 +82,31 @@ int socket(Thread *t, int domain, int type, int protocol) { releaseLock(&lock); return sd; } + +/* bind(): assigns a local address to a socket + * params: t - calling thread, NULL for kernel threads + * params: sd - socket descriptor + * params: addr - socket address structure + * params: len - length of socket address struct + * returns: zero on success, negative error code on fail + */ + +int bind(Thread *t, int sd, const struct sockaddr *addr, socklen_t len) { + Process *p; + if(t) p = getProcess(t->pid); + else p = getProcess(getPid()); + if(!p) return -ESRCH; + + // input verification + if(len > sizeof(struct sockaddr)) len = sizeof(struct sockaddr); + if(sd < 0 || sd >= MAX_IO_DESCRIPTORS) return -EBADF; + if(!p->io[sd].valid || p->io[sd].type != IO_SOCKET) return -ENOTSOCK; + + SocketDescriptor *sock = (SocketDescriptor *) p->io[sd].data; + if(!sock) return -ENOTSOCK; + if(addr->sa_family != sock->address.sa_family) return -EAFNOSUPPORT; + + // finally + memcpy(&sock->address, addr, len); + return 0; +} \ No newline at end of file From f861a3fa80a0ade21c5cbe629aee0df71a791aea Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 16:12:15 -0400 Subject: [PATCH 16/51] ipc: added nonblocking flags --- src/include/kernel/io.h | 6 ++++++ src/include/kernel/socket.h | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/src/include/kernel/io.h b/src/include/kernel/io.h index 3cd14ee8..a21fbfa0 100644 --- a/src/include/kernel/io.h +++ b/src/include/kernel/io.h @@ -24,11 +24,17 @@ #define IO_FILE 4 #define IO_SOCKET 5 +/* I/O descriptor flags */ +#define O_NONBLOCK 0x0001 +#define O_NDELAY O_NONBLOCK +#define O_CLOEXEC 0x0002 + // TODO: decide whether to implement named pipes as files or an independent type typedef struct IODescriptor { bool valid; int type; + uint16_t flags; void *data; // file or socket-specific data } IODescriptor; diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 729debd7..13247130 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -25,6 +25,10 @@ #define SOCK_DGRAM 2 // datagram-oriented #define SOCK_SEQPACKET 3 // connection-oriented +/* additional socket flags */ +#define SOCK_NONBLOCK 0x100 +#define SOCK_CLOEXEC 0x200 + typedef uint16_t sa_family_t; typedef size_t socklen_t; From 50eb798fa9198bf26d9fdad941c2f2166623c5ac Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 16:14:15 -0400 Subject: [PATCH 17/51] ipc: account for flags in socket() --- src/ipc/sockinit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index 75445bbd..62f9229f 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -65,6 +65,7 @@ int socket(Thread *t, int domain, int type, int protocol) { iod->type = IO_SOCKET; iod->data = calloc(1, sizeof(SocketDescriptor)); + iod->flags = type & 0xFF00; if(!iod->data) { releaseLock(&lock); closeIO(p, iod); @@ -73,7 +74,7 @@ int socket(Thread *t, int domain, int type, int protocol) { // set up the socket family for now SocketDescriptor *sock = (SocketDescriptor *)iod->data; sock->address.sa_family = domain; - sock->type = type; + sock->type = type & 0xFF; sock->protocol = protocol; sockets[socketCount] = sock; From 25f4b02799a308d90e7d9062fa1163e47b85727b Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 16:19:22 -0400 Subject: [PATCH 18/51] ipc: added listener to socket struct --- src/include/kernel/socket.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 13247130..1cb91499 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -47,6 +48,7 @@ struct sockaddr_un { /* socket-specific I/O descriptor (see io.h) */ typedef struct { struct sockaddr address; + bool listener; int type, protocol, backlog; int inboundCount, outboundCount; void **inbound, **outbound; From c606528976520babfdf9976dbd9c9e2068191b6e Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 16:42:58 -0400 Subject: [PATCH 19/51] ipc: changed max sockets to 262k --- src/include/kernel/socket.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 1cb91499..645de3f9 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -14,7 +14,7 @@ #include /* system-wide limit */ -#define MAX_SOCKETS (1 << 20) // little over a million +#define MAX_SOCKETS (1 << 18) // 262k /* socket family/domain - only Unix sockets will be implemented in the kernel */ #define AF_UNIX 1 From cdd2e1aef4f15a3c56cc2fa6ef254f84ee1b7aeb Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 16:49:42 -0400 Subject: [PATCH 20/51] ipc: find socket by address --- src/include/kernel/socket.h | 1 + src/ipc/sockinit.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 645de3f9..ccc1ca27 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -55,6 +55,7 @@ typedef struct { } SocketDescriptor; void socketInit(); +SocketDescriptor *getLocalSocket(const struct sockaddr *, socklen_t); /* socket system calls */ int socket(Thread *, int, int, int); diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index 62f9229f..0a5f0388 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -41,6 +41,24 @@ void socketInit() { KDEBUG("max %d sockets, %d per process\n", MAX_SOCKETS, MAX_IO_DESCRIPTORS); } +/* getLocalSocket(): finds a local socket by address + * params: addr - socket address + * params: len - length of socket address + * returns: pointer to socket descriptor, NULL on fail + */ + +SocketDescriptor *getLocalSocket(const struct sockaddr *addr, socklen_t len) { + if(!socketCount) return NULL; + if(len > sizeof(struct sockaddr)) len = sizeof(struct sockaddr); + for(int i = 0; i < socketCount; i++) { + if((sockets[i]) && !memcmp(&sockets[i]->address, addr, len)) { + return sockets[i]; + } + } + + return NULL; +} + /* socket(): opens a communication socket * params: t - calling thread, NULL for kernel threads * params: domain - socket domain/family From aa87cf003c72abc5e74c2fa3abeb8de4c6296ac0 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 17:03:15 -0400 Subject: [PATCH 21/51] ipc: adjusted socket descriptor structure for connection-oriented communication --- src/include/kernel/socket.h | 4 +++- src/ipc/sockinit.c | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index ccc1ca27..60d48308 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -46,12 +46,14 @@ struct sockaddr_un { }; /* socket-specific I/O descriptor (see io.h) */ -typedef struct { +typedef struct SocketDescriptor { + Process *process; struct sockaddr address; bool listener; int type, protocol, backlog; int inboundCount, outboundCount; void **inbound, **outbound; + struct SocketDescriptor *peer; } SocketDescriptor; void socketInit(); diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index 0a5f0388..a88889f1 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -91,6 +91,7 @@ int socket(Thread *t, int domain, int type, int protocol) { // set up the socket family for now SocketDescriptor *sock = (SocketDescriptor *)iod->data; + sock->process = p; sock->address.sa_family = domain; sock->type = type & 0xFF; sock->protocol = protocol; From 701f8d0685105e055174eef38cac7cc044b1d29c Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 20:21:43 -0400 Subject: [PATCH 22/51] ipc: expose socket spinlock --- src/include/kernel/socket.h | 2 ++ src/ipc/sockinit.c | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 60d48308..62412d79 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -58,6 +58,8 @@ typedef struct SocketDescriptor { void socketInit(); SocketDescriptor *getLocalSocket(const struct sockaddr *, socklen_t); +void socketLock(); +void socketRelease(); /* socket system calls */ int socket(Thread *, int, int, int); diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index a88889f1..bb17f4e2 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -59,6 +59,24 @@ SocketDescriptor *getLocalSocket(const struct sockaddr *addr, socklen_t len) { return NULL; } +/* socketLock(): acquires the socket descriptor spinlock + * params: none + * returns: nothing + */ + +void socketLock() { + acquireLockBlocking(&lock); +} + +/* socketRelease(): frees the socket descriptor spinlock + * params: none + * returns: nothing + */ + +void socketRelease() { + releaseLock(&lock); +} + /* socket(): opens a communication socket * params: t - calling thread, NULL for kernel threads * params: domain - socket domain/family From 3d657105552e3344c1f77553af0ff87c7f8ca28d Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 20:31:33 -0400 Subject: [PATCH 23/51] ipc: socket connect() --- src/include/kernel/socket.h | 5 ++-- src/ipc/connection.c | 50 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 src/ipc/connection.c diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 62412d79..693fb7a3 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -50,10 +50,11 @@ typedef struct SocketDescriptor { Process *process; struct sockaddr address; bool listener; - int type, protocol, backlog; + int type, protocol, backlogMax, backlogCount; int inboundCount, outboundCount; void **inbound, **outbound; - struct SocketDescriptor *peer; + struct SocketDescriptor **backlog; // for incoming connections via connect() + struct SocketDescriptor *peer; // for peer-to-peer connections } SocketDescriptor; void socketInit(); diff --git a/src/ipc/connection.c b/src/ipc/connection.c new file mode 100644 index 00000000..d15785f3 --- /dev/null +++ b/src/ipc/connection.c @@ -0,0 +1,50 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +/* Socket Connection Functions */ +/* connect(), listen(), and accept() are implemented here */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* connect(): creates a socket connection + * params: t - calling thread, NULL for kernel threads + * params: sd - socket descriptor + * params: addr - peer address + * params: len - length of peer address + * returns: zero on success, negative error code on fail + */ + +int connect(Thread *t, int sd, const struct sockaddr *addr, socklen_t len) { + Process *p; + if(t) p = getProcess(t->pid); + else p = getProcess(getPid()); + if(!p) return -ESRCH; + + if(!p->io[sd].valid || !p->io[sd].data || (p->io[sd].type != IO_SOCKET)) + return -ENOTSOCK; + + SocketDescriptor *self = (SocketDescriptor *) p->io[sd].data; + SocketDescriptor *peer = getLocalSocket(addr, len); + + if(!peer) return -EADDRNOTAVAIL; + if(!peer->listener || !peer->backlogMax || !peer->backlog) return -ECONNREFUSED; + if(peer->backlogCount >= peer->backlogMax) return -ETIMEDOUT; + + // at this point we're sure it's safe to create a connection + socketLock(); + peer->backlog[peer->backlogCount] = self; + peer->backlogCount++; + socketRelease(); + return 0; +} From b09a35307a48e2665c8c98e8a1c7c088b24f4c00 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 20:50:56 -0400 Subject: [PATCH 24/51] ipc: socket listen() --- src/include/kernel/socket.h | 3 ++- src/ipc/connection.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 693fb7a3..2cab57d7 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -13,8 +13,9 @@ #include #include -/* system-wide limit */ +/* system-wide limits */ #define MAX_SOCKETS (1 << 18) // 262k +#define SOCKET_DEFAULT_BACKLOG 1024 // default socket backlog size /* socket family/domain - only Unix sockets will be implemented in the kernel */ #define AF_UNIX 1 diff --git a/src/ipc/connection.c b/src/ipc/connection.c index d15785f3..4159534d 100644 --- a/src/ipc/connection.c +++ b/src/ipc/connection.c @@ -48,3 +48,37 @@ int connect(Thread *t, int sd, const struct sockaddr *addr, socklen_t len) { socketRelease(); return 0; } + +/* listen(): listens for incoming connections on a socket + * params: t - calling thread, NULL for kernel threads + * params: sd - socket descriptor + * params: backlog - maximum number of queued connections, zero for default + * returns: zero on success, negative error code on fail + */ + +int listen(Thread *t, int sd, int backlog) { + Process *p; + if(t) p = getProcess(t->pid); + else p = getProcess(getPid()); + if(!p) return -ESRCH; + + if(!p->io[sd].valid || !p->io[sd].data || (p->io[sd].type != IO_SOCKET)) + return -ENOTSOCK; + + socketLock(); + SocketDescriptor *sock = (SocketDescriptor *) p->io[sd].data; + sock->backlogCount = 0; + + if(backlog > 0) sock->backlogMax = backlog; + else sock->backlogMax = SOCKET_DEFAULT_BACKLOG; + + sock->backlog = calloc(backlog, sizeof(SocketDescriptor *)); + if(!sock->backlog) { + socketRelease(); + return -ENOBUFS; + } + + sock->listener = true; + socketRelease(); + return 0; +} From 5ce5aa15b6591527c8458de5ea639ebe6adc2a0f Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Fri, 6 Sep 2024 20:59:22 -0400 Subject: [PATCH 25/51] ipc: ensure protocol compatibility in connect() --- src/ipc/connection.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ipc/connection.c b/src/ipc/connection.c index 4159534d..6b80c8bf 100644 --- a/src/ipc/connection.c +++ b/src/ipc/connection.c @@ -38,6 +38,7 @@ int connect(Thread *t, int sd, const struct sockaddr *addr, socklen_t len) { SocketDescriptor *peer = getLocalSocket(addr, len); if(!peer) return -EADDRNOTAVAIL; + if(self->address.sa_family != peer->address.sa_family) return -EAFNOSUPPORT; if(!peer->listener || !peer->backlogMax || !peer->backlog) return -ECONNREFUSED; if(peer->backlogCount >= peer->backlogMax) return -ETIMEDOUT; From 5d1a96879c1dfe0dc49ddcdb6fca4e9f4f05d2ce Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 10:33:20 -0400 Subject: [PATCH 26/51] ipc: socket register function --- src/include/kernel/socket.h | 1 + src/ipc/sockinit.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 2cab57d7..2772c584 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -62,6 +62,7 @@ void socketInit(); SocketDescriptor *getLocalSocket(const struct sockaddr *, socklen_t); void socketLock(); void socketRelease(); +int socketRegister(SocketDescriptor *); /* socket system calls */ int socket(Thread *, int, int, int); diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index bb17f4e2..0f36b9e5 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -77,6 +77,18 @@ void socketRelease() { releaseLock(&lock); } +/* socketRegister(): registers an open socket + * params: sock - socket descriptor structure + * returns: zero on success + */ + +int socketRegister(SocketDescriptor *sock) { + if(socketCount >= MAX_SOCKETS) return -ENFILE; + sockets[socketCount] = sock; + socketCount++; + return 0; +} + /* socket(): opens a communication socket * params: t - calling thread, NULL for kernel threads * params: domain - socket domain/family @@ -92,6 +104,7 @@ int socket(Thread *t, int domain, int type, int protocol) { if(!p) return -ESRCH; if(p->iodCount == MAX_IO_DESCRIPTORS) return -EMFILE; + if(socket >= MAX_SOCKETS) return -ENFILE; acquireLockBlocking(&lock); From a910e3e81f1e56374805cfb754cd365138223d8f Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 10:44:13 -0400 Subject: [PATCH 27/51] ipc: socket accept() --- src/ipc/connection.c | 61 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/ipc/connection.c b/src/ipc/connection.c index 6b80c8bf..17209920 100644 --- a/src/ipc/connection.c +++ b/src/ipc/connection.c @@ -72,7 +72,7 @@ int listen(Thread *t, int sd, int backlog) { if(backlog > 0) sock->backlogMax = backlog; else sock->backlogMax = SOCKET_DEFAULT_BACKLOG; - + sock->backlog = calloc(backlog, sizeof(SocketDescriptor *)); if(!sock->backlog) { socketRelease(); @@ -83,3 +83,62 @@ int listen(Thread *t, int sd, int backlog) { socketRelease(); return 0; } + +/* accept(): accepts an incoming socket connection + * this function does NOT block at the kernel level - the syscall dispatcher + * will take care of blocking if the socket is not set to be non-blocking + * params: t - calling thread, NULL for kernel threads + * params: sd - socket descriptor + * params: addr - buffer to store peer's address + * params: len - length of the buffer on input, length of data stored on output + * returns: positive socket descriptor on success, negative error code on fail + */ + +int accept(Thread *t, int sd, struct sockaddr *addr, socklen_t *len) { + Process *p; + if(t) p = getProcess(t->pid); + else p = getProcess(getPid()); + if(!p) return -ESRCH; + + if(!p->io[sd].valid || !p->io[sd].data || (p->io[sd].type != IO_SOCKET)) + return -ENOTSOCK; + + SocketDescriptor *listener = (SocketDescriptor *)p->io[sd].data; + if(!listener->listener || !listener->backlog || !listener->backlogMax) + return -EINVAL; // socket is not listening + + if(!listener->backlogCount) + return -EWOULDBLOCK; // socket has no incoming queue + + socketLock(); + + // create a new connected socket + IODescriptor *iod = NULL; + int connectedSocket = openIO(p, (void **) &iod); + if((connectedSocket < 0) || !iod) { + socketRelease(); + return -EMFILE; + } + + iod->type = IO_SOCKET; + iod->flags = p->io[sd].flags; + iod->data = calloc(1, sizeof(SocketDescriptor)); + if(!iod->data) { + socketRelease(); + closeIO(p, iod); + return -ENOMEM; + } + + // copy the self address + SocketDescriptor *self = (SocketDescriptor *)iod->data; + memcpy(&self->address, &listener->address, sizeof(struct sockaddr)); + self->type = listener->type; + self->protocol = listener->protocol; + + // and assign the peer address + self->peer = listener->backlog[0]; // TODO: is this always FIFO? + memmove(&listener->backlog[0], &listener->backlog[1], (listener->backlogMax - 1) * sizeof(SocketDescriptor *)); + + socketRelease(); + return connectedSocket; +} From e5a06859c52530cb2fedd41f3e26b29c1b150cb2 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 10:52:26 -0400 Subject: [PATCH 28/51] syscalls: allow for blocking syscalls --- src/include/kernel/syscalls.h | 2 +- src/syscalls/dispatch.c | 10 +++++++++- src/syscalls/queue.c | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/include/kernel/syscalls.h b/src/include/kernel/syscalls.h index 6cf90a48..2f5d7d62 100644 --- a/src/include/kernel/syscalls.h +++ b/src/include/kernel/syscalls.h @@ -14,7 +14,7 @@ #define MAX_SYSCALL 12 // for now typedef struct SyscallRequest { - bool busy, queued; + bool busy, queued, unblock; uint64_t function; uint64_t params[4]; diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index 32f28114..d680fb22 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -20,18 +20,22 @@ void syscallDispatchExit(SyscallRequest *req) { void syscallDispatchFork(SyscallRequest *req) { req->ret = fork(req->thread); + req->unblock = true; } void syscallDispatchYield(SyscallRequest *req) { req->ret = yield(req->thread); + req->unblock = true; } void syscallDispatchGetPID(SyscallRequest *req) { req->ret = req->thread->pid; + req->unblock = true; } void syscallDispatchGetTID(SyscallRequest *req) { req->ret = req->thread->tid; + req->unblock = true; } void syscallDispatchGetUID(SyscallRequest *req) { @@ -42,6 +46,8 @@ void syscallDispatchGetUID(SyscallRequest *req) { } else { req->ret = p->user; } + + req->unblock = true; } void syscallDispatchGetGID(SyscallRequest *req) { @@ -52,6 +58,8 @@ void syscallDispatchGetGID(SyscallRequest *req) { } else { req->ret = p->group; } + + req->unblock = true; } void syscallDispatchMSleep(SyscallRequest *req) { @@ -59,7 +67,7 @@ void syscallDispatchMSleep(SyscallRequest *req) { } void (*syscallDispatchTable[])(SyscallRequest *) = { - // group 1: scheduler functions + /* group 1: scheduler functions */ syscallDispatchExit, // 0 - exit() syscallDispatchFork, // 1 - fork() syscallDispatchYield, // 2 - yield() diff --git a/src/syscalls/queue.c b/src/syscalls/queue.c index f6b75e64..e6269801 100644 --- a/src/syscalls/queue.c +++ b/src/syscalls/queue.c @@ -96,7 +96,7 @@ int syscallProcess() { platformSetContextStatus(syscall->thread->context, syscall->ret); } - if(syscall->thread->status == THREAD_BLOCKED) { + if((syscall->thread->status == THREAD_BLOCKED) && syscall->unblock) { // this way we prevent accidentally running threads that exit() syscall->thread->status = THREAD_QUEUED; syscall->thread->time = schedTimeslice(syscall->thread, syscall->thread->priority); From b673281e356ba707ad03b0fd7720a64fdd8613c0 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 11:13:08 -0400 Subject: [PATCH 29/51] ipc: fix for I/O descriptor flags --- src/ipc/sockinit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index 0f36b9e5..a65502df 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -114,7 +114,7 @@ int socket(Thread *t, int domain, int type, int protocol) { iod->type = IO_SOCKET; iod->data = calloc(1, sizeof(SocketDescriptor)); - iod->flags = type & 0xFF00; + iod->flags = type >> 8; if(!iod->data) { releaseLock(&lock); closeIO(p, iod); From cef9e0825b9ba15a2feac07d82bfd0889732b151 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 11:13:43 -0400 Subject: [PATCH 30/51] syscalls: added socket syscalls --- src/include/kernel/syscalls.h | 2 +- src/syscalls/dispatch.c | 103 ++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/src/include/kernel/syscalls.h b/src/include/kernel/syscalls.h index 2f5d7d62..09b3400e 100644 --- a/src/include/kernel/syscalls.h +++ b/src/include/kernel/syscalls.h @@ -11,7 +11,7 @@ #include #include -#define MAX_SYSCALL 12 // for now +#define MAX_SYSCALL 37 // for now typedef struct SyscallRequest { bool busy, queued, unblock; diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index d680fb22..e1a5ffd4 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -6,7 +6,11 @@ */ #include +#include +#include +#include #include +#include #include #include @@ -14,6 +18,26 @@ * their behavior. This ensures the exposed functionality is always as close * as possible to the Unix specification */ +/* syscallVerifyPointer(): ensure user programs don't violate memory permissions + * params: req - syscall request + * params: base - base pointer + * params: len - length of the structure at the point + * returns: true if safe, false if unsafe, user program terminated as well + */ + +bool syscallVerifyPointer(SyscallRequest *req, uintptr_t base, uintptr_t len) { + uintptr_t end = base + len; + if(base < USER_BASE_ADDRESS || end > USER_LIMIT_ADDRESS) { + KWARN("killing tid %d for memory access violation at 0x%X (%d)\n", req->thread->tid, base, len); + terminateThread(req->thread, -1, false); + return false; + } + + return true; +} + +/* Group 1: Scheduler */ + void syscallDispatchExit(SyscallRequest *req) { exit(req->thread, req->params[0]); } @@ -66,6 +90,56 @@ void syscallDispatchMSleep(SyscallRequest *req) { req->ret = msleep(req->thread, req->params[0]); } +/* TODO: Group 2: File System */ + +/* Group 3: Interprocess Communication */ + +void syscallDispatchSocket(SyscallRequest *req) { + req->ret = socket(req->thread, req->params[0], req->params[1], req->params[2]); + req->unblock = true; +} + +void syscallDispatchConnect(SyscallRequest *req) { + if(syscallVerifyPointer(req, req->params[1], req->params[2])) { + req->ret = connect(req->thread, req->params[0], (const struct sockaddr *)req->params[1], req->params[2]); + req->unblock = true; + } +} + +void syscallDispatchBind(SyscallRequest *req) { + if(syscallVerifyPointer(req, req->params[1], req->params[2])) { + req->ret = bind(req->thread, req->params[0], (const struct sockaddr *)req->params[1], req->params[2]); + req->unblock = true; + } +} + +void syscallDispatchListen(SyscallRequest *req) { + req->ret = listen(req->thread, req->params[0], req->params[1]); + req->unblock = true; +} + +void syscallDispatchAccept(SyscallRequest *req) { + int status; + if(!req->params[1]) { + status = accept(req->thread, req->params[0], NULL, NULL); + } else { + if(syscallVerifyPointer(req, req->params[1], sizeof(const struct sockaddr)) && + syscallVerifyPointer(req, req->params[2], sizeof(socklen_t))) { + status = accept(req->thread, req->params[0], (struct sockaddr *)req->params[1], (socklen_t *)req->params[2]); + } + } + + if(status == -EWOULDBLOCK || status == -EAGAIN) { + // return without unblocking if necessary + Process *p = getProcess(req->thread->pid); + if(!(p->io[req->params[0]].flags & O_NONBLOCK)) + req->unblock = false; + } else { + req->ret = status; + req->unblock = true; + } +} + void (*syscallDispatchTable[])(SyscallRequest *) = { /* group 1: scheduler functions */ syscallDispatchExit, // 0 - exit() @@ -81,4 +155,33 @@ void (*syscallDispatchTable[])(SyscallRequest *) = { NULL, // 10 - setuid() NULL, // 11 - setgid() syscallDispatchMSleep, // 12 - msleep() + + /* group 2: file system manipulation */ + NULL, // 13 - open() + NULL, // 14 - close() + NULL, // 15 - read() + NULL, // 16 - write() + NULL, // 17 - stat() + NULL, // 18 - lseek() + NULL, // 19 - chown() + NULL, // 20 - chmod() + NULL, // 21 - link() + NULL, // 22 - unlink() + NULL, // 23 - mknod() + NULL, // 24 - mkdir() + NULL, // 25 - rmdir() + NULL, // 26 - utime() + NULL, // 27 - chroot() + NULL, // 28 - mount() + NULL, // 29 - umount() + NULL, // 30 - fnctl() + + /* group 3: interprocess communication */ + syscallDispatchSocket, // 31 - socket() + syscallDispatchConnect, // 32 - connect() + syscallDispatchBind, // 33 - bind() + syscallDispatchListen, // 34 - listen() + syscallDispatchAccept, // 35 - accept() + NULL, // 36 - recv() + NULL, // 37 - send() }; From 2df1cfb114d737aac2b39abda26cd403b7c6e158 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 12:28:36 -0400 Subject: [PATCH 31/51] syscalls: use thread paging context during syscall handling --- src/syscalls/queue.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/syscalls/queue.c b/src/syscalls/queue.c index e6269801..d7c34204 100644 --- a/src/syscalls/queue.c +++ b/src/syscalls/queue.c @@ -92,8 +92,10 @@ int syscallProcess() { terminateThread(syscall->thread, -1, false); schedRelease(); } else { + threadUseContext(syscall->thread->tid); syscallDispatchTable[syscall->function](syscall); platformSetContextStatus(syscall->thread->context, syscall->ret); + //threadUseContext(getTid()); } if((syscall->thread->status == THREAD_BLOCKED) && syscall->unblock) { From 6e4bedc773369606fe49f1987b5977d9b0ad930a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 12:33:11 -0400 Subject: [PATCH 32/51] io: bug fix where pointers were not stored --- src/io.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/io.c b/src/io.c index 5c522a72..b8c82f9e 100644 --- a/src/io.c +++ b/src/io.c @@ -20,7 +20,7 @@ int openIO(void *pv, void **iodv) { Process *p = (Process *)pv; - IODescriptor *iod = (IODescriptor *)iodv; + IODescriptor **iod = (IODescriptor **)iodv; if(p->iodCount >= MAX_IO_DESCRIPTORS) return -ESRCH; @@ -35,6 +35,8 @@ int openIO(void *pv, void **iodv) { p->io[desc].data = NULL; p->iodCount++; + + *iod = &p->io[desc]; return desc; } From 1e513de9e069a3228c60e3d443550d249dc94311 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 12:33:35 -0400 Subject: [PATCH 33/51] ipc: bug fix in socket creation --- src/ipc/sockinit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/sockinit.c b/src/ipc/sockinit.c index a65502df..f04c60d8 100644 --- a/src/ipc/sockinit.c +++ b/src/ipc/sockinit.c @@ -104,7 +104,7 @@ int socket(Thread *t, int domain, int type, int protocol) { if(!p) return -ESRCH; if(p->iodCount == MAX_IO_DESCRIPTORS) return -EMFILE; - if(socket >= MAX_SOCKETS) return -ENFILE; + if(socketCount >= MAX_SOCKETS) return -ENFILE; acquireLockBlocking(&lock); From 9aab9311b7a59c688edda44c0e76331e5f458f2c Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 13:31:14 -0400 Subject: [PATCH 34/51] x86_64: fixed a subtle bug in page context cloning --- src/platform/x86_64/cpu/paging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/x86_64/cpu/paging.c b/src/platform/x86_64/cpu/paging.c index b4039b3c..dabe33b3 100644 --- a/src/platform/x86_64/cpu/paging.c +++ b/src/platform/x86_64/cpu/paging.c @@ -287,7 +287,7 @@ void *platformCloneUserSpace(uintptr_t parent) { uint64_t ptr = oldPML4[i] & ~(PAGE_SIZE-1); uint64_t flags = oldPML4[i] & (PAGE_SIZE-1); if(oldPML4[i]) { - newPML4[i] = clonePagingLayer(ptr, 1) | flags; + newPML4[i] = clonePagingLayer(ptr, 0) | flags; } } From e0513f61d63ceef012e3b0b4d6c4f17149d6f487 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 13:31:47 -0400 Subject: [PATCH 35/51] sched: fork() clones I/O descriptors --- src/sched/fork.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/sched/fork.c b/src/sched/fork.c index fbbcc136..58019f15 100644 --- a/src/sched/fork.c +++ b/src/sched/fork.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -77,9 +78,15 @@ pid_t fork(Thread *t) { return -1; } + // clone I/O descriptors + Process *parent = getProcess(t->pid); + if(parent) { + memcpy(p->io, parent->io, sizeof(IODescriptor) * MAX_IO_DESCRIPTORS); + p->iodCount = parent->iodCount; + } + // if we made this far then the creation was successful // list the child process as a child of the parent - Process *parent = getProcess(t->pid); if(parent) { parent->childrenCount++; parent->children = realloc(parent->children, parent->childrenCount); From 5fa80357d1cdf1ff756100b17737e452ee8bacb9 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 13:32:19 -0400 Subject: [PATCH 36/51] sched: debugging function to dump thread queue --- src/include/kernel/sched.h | 1 + src/sched/sched.c | 39 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 26b243f2..dd377488 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -85,6 +85,7 @@ void setScheduling(bool); void blockThread(Thread *); void unblockThread(Thread *); Process *getProcessQueue(); +void schedStatus(); pid_t kthreadCreate(void *(*)(void *), void *); pid_t processCreate(); diff --git a/src/sched/sched.c b/src/sched/sched.c index 7d2e5fb9..ec0deb66 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -580,3 +580,42 @@ void setLumenPID(pid_t pid) { pid_t getLumenPID() { return lumen; } + +/* schedStatus(): dumps the queue of threads + */ + +void schedStatus() { + Process *p = first; + + while(p) { + if(p->threadCount && p->threads) { + Thread *t = p->threads[0]; + + while(t) { + switch(t->status) { + case THREAD_BLOCKED: + KDEBUG("pid %d tid %d: blocked\n", t->pid, t->tid); + break; + case THREAD_RUNNING: + KDEBUG("pid %d tid %d: running\n", t->pid, t->tid); + break; + case THREAD_QUEUED: + KDEBUG("pid %d tid %d: queued\n", t->pid, t->tid); + break; + case THREAD_SLEEP: + KDEBUG("pid %d tid %d: sleeping\n", t->pid, t->tid); + break; + case THREAD_ZOMBIE: + KDEBUG("pid %d tid %d: zombie\n", t->pid, t->tid); + break; + default: + KDEBUG("pid %d tid %d: undefined status %d\n", t->pid, t->tid, t->status); + } + + t = t->next; + } + } + + p = p->next; + } +} \ No newline at end of file From d9f1d77e7feefb7b4eb97d359eef1eda83c9365a Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 13:39:15 -0400 Subject: [PATCH 37/51] syscalls: fix blocking dispatcher --- src/syscalls/dispatch.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index e1a5ffd4..f173fa85 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -132,12 +132,18 @@ void syscallDispatchAccept(SyscallRequest *req) { if(status == -EWOULDBLOCK || status == -EAGAIN) { // return without unblocking if necessary Process *p = getProcess(req->thread->pid); - if(!(p->io[req->params[0]].flags & O_NONBLOCK)) + if(!(p->io[req->params[0]].flags & O_NONBLOCK)) { + // block by putting the syscall back in the queue req->unblock = false; - } else { - req->ret = status; - req->unblock = true; + req->busy = false; + req->queued = true; + syscallEnqueue(req); + return; + } } + + req->ret = status; + req->unblock = true; } void (*syscallDispatchTable[])(SyscallRequest *) = { From 455d0120c6ddf5233af9ffb4c1a076d1ff3a9d73 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 14:01:40 -0400 Subject: [PATCH 38/51] syscalls: additional fixes for blocking syscalls --- src/syscalls/dispatch.c | 1 + src/syscalls/queue.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index f173fa85..06fbc1af 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -137,6 +137,7 @@ void syscallDispatchAccept(SyscallRequest *req) { req->unblock = false; req->busy = false; req->queued = true; + req->next = NULL; syscallEnqueue(req); return; } diff --git a/src/syscalls/queue.c b/src/syscalls/queue.c index d7c34204..40957bf4 100644 --- a/src/syscalls/queue.c +++ b/src/syscalls/queue.c @@ -102,8 +102,8 @@ int syscallProcess() { // this way we prevent accidentally running threads that exit() syscall->thread->status = THREAD_QUEUED; syscall->thread->time = schedTimeslice(syscall->thread, syscall->thread->priority); + syscall->busy = false; } - syscall->busy = false; return 1; } \ No newline at end of file From e7a5a2567d1d500a5eb670cea7c6c3db316e9957 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 14:02:07 -0400 Subject: [PATCH 39/51] sched: show remaining time slice in queue dump --- src/sched/sched.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sched/sched.c b/src/sched/sched.c index ec0deb66..bd3e16b2 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -597,13 +597,13 @@ void schedStatus() { KDEBUG("pid %d tid %d: blocked\n", t->pid, t->tid); break; case THREAD_RUNNING: - KDEBUG("pid %d tid %d: running\n", t->pid, t->tid); + KDEBUG("pid %d tid %d: running (%d)\n", t->pid, t->tid, t->time); break; case THREAD_QUEUED: - KDEBUG("pid %d tid %d: queued\n", t->pid, t->tid); + KDEBUG("pid %d tid %d: queued (%d)\n", t->pid, t->tid, t->time); break; case THREAD_SLEEP: - KDEBUG("pid %d tid %d: sleeping\n", t->pid, t->tid); + KDEBUG("pid %d tid %d: sleeping (%d)\n", t->pid, t->tid, t->time); break; case THREAD_ZOMBIE: KDEBUG("pid %d tid %d: zombie\n", t->pid, t->tid); From d80cb8ac64c61b35d4f2d9fc7305bc1c80de47c0 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 14:03:47 -0400 Subject: [PATCH 40/51] ipc: decrement backlog and check for null pointers in accept() --- src/ipc/connection.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/ipc/connection.c b/src/ipc/connection.c index 17209920..84565c04 100644 --- a/src/ipc/connection.c +++ b/src/ipc/connection.c @@ -134,11 +134,15 @@ int accept(Thread *t, int sd, struct sockaddr *addr, socklen_t *len) { memcpy(&self->address, &listener->address, sizeof(struct sockaddr)); self->type = listener->type; self->protocol = listener->protocol; + self->process = listener->process; // and assign the peer address self->peer = listener->backlog[0]; // TODO: is this always FIFO? memmove(&listener->backlog[0], &listener->backlog[1], (listener->backlogMax - 1) * sizeof(SocketDescriptor *)); + listener->backlogCount--; socketRelease(); - return connectedSocket; + + if(!self->peer) return -ECONNABORTED; + else return connectedSocket; } From a11e5e8f9d7826644b0b095c143fca9a12ebb214 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 17:31:42 -0400 Subject: [PATCH 41/51] errno: typo --- src/include/errno.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/errno.h b/src/include/errno.h index c04ee66c..911ed62d 100644 --- a/src/include/errno.h +++ b/src/include/errno.h @@ -61,7 +61,7 @@ #define ENOPROTOOPT 50 // protocol not implemented #define ENOSPC 51 // ran out of storage #define ENOSYS 52 // function not supported -#define ENOCONN 53 // socket not connected +#define ENOTCONN 53 // socket not connected #define ENOTDIR 54 // not a directory nor symlink to directory #define ENOTEMPTY 55 // directory not empty #define ENOTRECOVERABLE 56 // unrecoverable error From 53664e36896b77159a225f6b37d39a0e2ff65804 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 17:32:20 -0400 Subject: [PATCH 42/51] ipc: send() for unix sockets --- src/ipc/sockio.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 src/ipc/sockio.c diff --git a/src/ipc/sockio.c b/src/ipc/sockio.c new file mode 100644 index 00000000..f9b86bb6 --- /dev/null +++ b/src/ipc/sockio.c @@ -0,0 +1,73 @@ +/* + * lux - a lightweight unix-like operating system + * Omar Elghoul, 2024 + * + * Core Microkernel + */ + +/* Socket I/O Functions */ +/* send() and recv() are implemented here */ + +#include +#include +#include +#include +#include +#include +#include + +/* send(): sends a message to a socket connection + * params: t - calling thread + * params: sd - socket descriptor + * params: buffer - buffer containing the message + * params: len - size of the message + * params: flags - optional flags for the request + * returns: positive number of bytes sent, negative error code on fail + */ + +ssize_t send(Thread *t, int sd, const void *buffer, size_t len, int flags) { + Process *p; + if(t) p = getProcess(t->pid); + else p = getProcess(getPid()); + if(!p) return -ESRCH; + + if(!p->io[sd].valid || !p->io[sd].data || (p->io[sd].type != IO_SOCKET)) + return -ENOTSOCK; + + SocketDescriptor *self = (SocketDescriptor*) p->io[sd].data; + SocketDescriptor *peer = self->peer; + if(!peer) return -EDESTADDRREQ; // not in connection mode + + sa_family_t family = self->address.sa_family; + + socketLock(); + + if(family == AF_UNIX || family == AF_LOCAL) { + // simply append to the peer's inbound list + void **newlist = realloc(peer->inbound, (peer->inboundCount + 1) * sizeof(void *)); + if(!newlist) { + socketRelease(); + return -ENOBUFS; + } + + void *message = malloc(len); + if(!message) { + free(newlist); + socketRelease(); + return -ENOBUFS; + } + + // and send + memcpy(message, buffer, len); + newlist[peer->inboundCount] = message; + peer->inboundCount++; + peer->inbound = newlist; + + socketRelease(); + return len; + } else { + /* TODO: handle other protocols in user space */ + socketRelease(); + return -ENOTCONN; + } +} From cf69a83b026cd9c9ca7e15cd689256690e817ef3 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 17:46:24 -0400 Subject: [PATCH 43/51] ipc: track lengths of data sent via sockets --- src/include/kernel/socket.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/kernel/socket.h b/src/include/kernel/socket.h index 2772c584..6dca5559 100644 --- a/src/include/kernel/socket.h +++ b/src/include/kernel/socket.h @@ -54,6 +54,7 @@ typedef struct SocketDescriptor { int type, protocol, backlogMax, backlogCount; int inboundCount, outboundCount; void **inbound, **outbound; + size_t *inboundLen, *outboundLen; struct SocketDescriptor **backlog; // for incoming connections via connect() struct SocketDescriptor *peer; // for peer-to-peer connections } SocketDescriptor; From 7617cd47555c634e76ca27457d3ad49e0d05419f Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 17:46:34 -0400 Subject: [PATCH 44/51] ipc: socket recv() --- src/ipc/sockio.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/src/ipc/sockio.c b/src/ipc/sockio.c index f9b86bb6..8763cf1e 100644 --- a/src/ipc/sockio.c +++ b/src/ipc/sockio.c @@ -44,12 +44,14 @@ ssize_t send(Thread *t, int sd, const void *buffer, size_t len, int flags) { if(family == AF_UNIX || family == AF_LOCAL) { // simply append to the peer's inbound list - void **newlist = realloc(peer->inbound, (peer->inboundCount + 1) * sizeof(void *)); + void **newlist = realloc(peer->inbound, (peer->inboundCount+1) * sizeof(void *)); if(!newlist) { socketRelease(); return -ENOBUFS; } + size_t *newlen = realloc(peer->inboundLen, (peer->inboundCount+1) * sizeof(size_t)); + void *message = malloc(len); if(!message) { free(newlist); @@ -60,8 +62,10 @@ ssize_t send(Thread *t, int sd, const void *buffer, size_t len, int flags) { // and send memcpy(message, buffer, len); newlist[peer->inboundCount] = message; + newlen[peer->inboundCount] = len; peer->inboundCount++; peer->inbound = newlist; + peer->inboundLen = newlen; socketRelease(); return len; @@ -71,3 +75,65 @@ ssize_t send(Thread *t, int sd, const void *buffer, size_t len, int flags) { return -ENOTCONN; } } + +/* recv(): receives a message from a socket connection + * params: t - calling thread + * params: sd - socket descriptor + * params: buffer - buffer to store message + * params: len - maximum size of the buffer + * params: flags - optional flags for the request + * returns: positive number of bytes received, negative error code on fail + */ + +ssize_t recv(Thread *t, int sd, void *buffer, size_t len, int flags) { + Process *p; + if(t) p = getProcess(t->pid); + else p = getProcess(getPid()); + if(!p) return -ESRCH; + + if(!p->io[sd].valid || !p->io[sd].data || (p->io[sd].type != IO_SOCKET)) + return -ENOTSOCK; + + SocketDescriptor *self = (SocketDescriptor*) p->io[sd].data; + if(!self->peer) return -EDESTADDRREQ; // not in connection mode + + sa_family_t family = self->address.sa_family; + if(!self->inboundCount || !self->inbound || !self->inboundLen) + return -EWOULDBLOCK; // no messages available + + socketLock(); + + if(family == AF_UNIX || family == AF_LOCAL) { + // copy from the inbound list + void *message = self->inbound[0]; // FIFO + size_t truelen = self->inboundLen[0]; + + if(!message) { + socketRelease(); + return -EWOULDBLOCK; + } + + if(truelen > len) truelen = len; // truncate longer messages + memcpy(buffer, message, truelen); + + // and remove the received message from the queue + free(message); + + self->inboundCount--; + if(!self->inboundCount) { + free(self->inbound); + free(self->inboundLen); + } else { + memmove(&self->inbound[0], &self->inbound[1], self->inboundCount * sizeof(void *)); + memmove(&self->inboundLen[0], &self->inboundLen[1], self->inboundCount * sizeof(size_t)); + self->inbound = realloc(self->inbound, self->inboundCount * sizeof(void *)); + self->inboundLen = realloc(self->inboundLen, self->inboundCount * sizeof(void *)); + } + + return truelen; + } else { + /* TODO: handle other protocols in user space */ + socketRelease(); + return -ENOTCONN; + } +} \ No newline at end of file From 67aa54ec80d72a070408afa1f3dfbfd9aa0326b4 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 17:52:04 -0400 Subject: [PATCH 45/51] syscalls: exposed recv() and send() --- src/syscalls/dispatch.c | 54 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index 06fbc1af..dc894120 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -147,6 +147,56 @@ void syscallDispatchAccept(SyscallRequest *req) { req->unblock = true; } +void syscallDispatchRecv(SyscallRequest *req) { + ssize_t status; + if(syscallVerifyPointer(req, req->params[1], req->params[2])) { + status = recv(req->thread, req->params[0], (void *)req->params[1], req->params[2], req->params[3]); + + // block the thread if necessary + if(status == -EWOULDBLOCK || status == -EAGAIN) { + // return without unblocking if necessary + Process *p = getProcess(req->thread->pid); + if(!(p->io[req->params[0]].flags & O_NONBLOCK)) { + // block by putting the syscall back in the queue + req->unblock = false; + req->busy = false; + req->queued = true; + req->next = NULL; + syscallEnqueue(req); + return; + } + } + + req->ret = status; + req->unblock = true; + } +} + +void syscallDispatchSend(SyscallRequest *req) { + ssize_t status; + if(syscallVerifyPointer(req, req->params[1], req->params[2])) { + status = send(req->thread, req->params[0], (const void *)req->params[1], req->params[2], req->params[3]); + + // block the thread if necessary + if(status == -EWOULDBLOCK || status == -EAGAIN) { + // return without unblocking if necessary + Process *p = getProcess(req->thread->pid); + if(!(p->io[req->params[0]].flags & O_NONBLOCK)) { + // block by putting the syscall back in the queue + req->unblock = false; + req->busy = false; + req->queued = true; + req->next = NULL; + syscallEnqueue(req); + return; + } + } + + req->ret = status; + req->unblock = true; + } +} + void (*syscallDispatchTable[])(SyscallRequest *) = { /* group 1: scheduler functions */ syscallDispatchExit, // 0 - exit() @@ -189,6 +239,6 @@ void (*syscallDispatchTable[])(SyscallRequest *) = { syscallDispatchBind, // 33 - bind() syscallDispatchListen, // 34 - listen() syscallDispatchAccept, // 35 - accept() - NULL, // 36 - recv() - NULL, // 37 - send() + syscallDispatchRecv, // 36 - recv() + syscallDispatchSend, // 37 - send() }; From 0664e518f0d1f4bae6680ffd9eacdbd2038db479 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 17:55:37 -0400 Subject: [PATCH 46/51] ipc: release socket spinlock after recv() --- src/ipc/sockio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ipc/sockio.c b/src/ipc/sockio.c index 8763cf1e..d387ed7e 100644 --- a/src/ipc/sockio.c +++ b/src/ipc/sockio.c @@ -130,6 +130,7 @@ ssize_t recv(Thread *t, int sd, void *buffer, size_t len, int flags) { self->inboundLen = realloc(self->inboundLen, self->inboundCount * sizeof(void *)); } + socketRelease(); return truelen; } else { /* TODO: handle other protocols in user space */ From cacc7b598fb66b3659ea8e83aefe77e650519d07 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 18:03:07 -0400 Subject: [PATCH 47/51] ipc: fix in connect() where peer wasn't being assigned to self --- src/ipc/connection.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ipc/connection.c b/src/ipc/connection.c index 84565c04..50b2d849 100644 --- a/src/ipc/connection.c +++ b/src/ipc/connection.c @@ -46,6 +46,7 @@ int connect(Thread *t, int sd, const struct sockaddr *addr, socklen_t len) { socketLock(); peer->backlog[peer->backlogCount] = self; peer->backlogCount++; + self->peer = peer; socketRelease(); return 0; } From aa9f649b1b9c8a67ba8358847b75f1c1178ceaeb Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 18:16:08 -0400 Subject: [PATCH 48/51] ipc: fix connection peers --- src/ipc/connection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipc/connection.c b/src/ipc/connection.c index 50b2d849..839f48db 100644 --- a/src/ipc/connection.c +++ b/src/ipc/connection.c @@ -46,7 +46,6 @@ int connect(Thread *t, int sd, const struct sockaddr *addr, socklen_t len) { socketLock(); peer->backlog[peer->backlogCount] = self; peer->backlogCount++; - self->peer = peer; socketRelease(); return 0; } @@ -139,6 +138,7 @@ int accept(Thread *t, int sd, struct sockaddr *addr, socklen_t *len) { // and assign the peer address self->peer = listener->backlog[0]; // TODO: is this always FIFO? + self->peer->peer = self; memmove(&listener->backlog[0], &listener->backlog[1], (listener->backlogMax - 1) * sizeof(SocketDescriptor *)); listener->backlogCount--; From f5e408abcd79850435f9f877f6844bc8103c77a8 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 18:27:08 -0400 Subject: [PATCH 49/51] sched: changed thread time slices --- src/include/kernel/sched.h | 9 ++++----- src/sched/sched.c | 11 ++--------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index dd377488..785c807b 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -14,9 +14,8 @@ #include #include -// ideal number of context switches per second // still not sure of how to decide on this value so it'll probably change -#define SCHED_SWITCH_RATE 200 +#define SCHED_TIME_SLICE 1 // ms #define MAX_PID 99999 @@ -26,9 +25,9 @@ #define THREAD_ZOMBIE 3 #define THREAD_SLEEP 4 -#define PRIORITY_HIGH 0 -#define PRIORITY_NORMAL 1 -#define PRIORITY_LOW 2 +#define PRIORITY_LOW 1 +#define PRIORITY_NORMAL 2 +#define PRIORITY_HIGH 3 typedef struct Thread { int status, cpu, priority; diff --git a/src/sched/sched.c b/src/sched/sched.c index bd3e16b2..31469a15 100644 --- a/src/sched/sched.c +++ b/src/sched/sched.c @@ -473,15 +473,8 @@ int threadUseContext(pid_t tid) { */ uint64_t schedTimeslice(Thread *t, int p) { - /* todo: actually interpret the priority value */ - uint64_t schedTime = PLATFORM_TIMER_FREQUENCY / SCHED_SWITCH_RATE; - - int cpus = platformCountCPU(); - uint64_t time = schedTime / threads; - if(time < 6) time = 6; // minimum threshold - time *= cpus; - if(time < 12) time = 12; - + if(!p) p = PRIORITY_NORMAL; + uint64_t time = p * SCHED_TIME_SLICE; t->priority = p; return time; } From dc9e8bc23801a3bfac7bb8c357b543873033ab8c Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 18:43:50 -0400 Subject: [PATCH 50/51] ipc: fix potential memory leak in send() --- src/ipc/sockio.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/ipc/sockio.c b/src/ipc/sockio.c index d387ed7e..6011ce8c 100644 --- a/src/ipc/sockio.c +++ b/src/ipc/sockio.c @@ -52,9 +52,16 @@ ssize_t send(Thread *t, int sd, const void *buffer, size_t len, int flags) { size_t *newlen = realloc(peer->inboundLen, (peer->inboundCount+1) * sizeof(size_t)); + if(!newlen) { + free(newlist); + socketRelease(); + return -ENOBUFS; + } + void *message = malloc(len); if(!message) { free(newlist); + free(newlen); socketRelease(); return -ENOBUFS; } From 3aee11584fbe6ce770ebc0752eeda9be7be76210 Mon Sep 17 00:00:00 2001 From: jewelcodes Date: Sat, 7 Sep 2024 18:46:47 -0400 Subject: [PATCH 51/51] syscalls: reduce variable scope where unnecessary --- src/syscalls/dispatch.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/syscalls/dispatch.c b/src/syscalls/dispatch.c index dc894120..82ea4b8c 100644 --- a/src/syscalls/dispatch.c +++ b/src/syscalls/dispatch.c @@ -148,9 +148,8 @@ void syscallDispatchAccept(SyscallRequest *req) { } void syscallDispatchRecv(SyscallRequest *req) { - ssize_t status; if(syscallVerifyPointer(req, req->params[1], req->params[2])) { - status = recv(req->thread, req->params[0], (void *)req->params[1], req->params[2], req->params[3]); + ssize_t status = recv(req->thread, req->params[0], (void *)req->params[1], req->params[2], req->params[3]); // block the thread if necessary if(status == -EWOULDBLOCK || status == -EAGAIN) { @@ -173,9 +172,8 @@ void syscallDispatchRecv(SyscallRequest *req) { } void syscallDispatchSend(SyscallRequest *req) { - ssize_t status; if(syscallVerifyPointer(req, req->params[1], req->params[2])) { - status = send(req->thread, req->params[0], (const void *)req->params[1], req->params[2], req->params[3]); + ssize_t status = send(req->thread, req->params[0], (const void *)req->params[1], req->params[2], req->params[3]); // block the thread if necessary if(status == -EWOULDBLOCK || status == -EAGAIN) {