From 1287f9dfe987f0456e4fb0741385d5f0278ef53b Mon Sep 17 00:00:00 2001
From: Marvin Borner
Date: Sun, 14 Feb 2021 17:07:29 +0100
Subject: Message waiting and more!

---
 kernel/drivers/ide.c      |  6 +--
 kernel/drivers/keyboard.c |  5 +--
 kernel/drivers/mouse.c    |  5 +--
 kernel/features/fs.c      | 36 ++++++++++++++---
 kernel/features/proc.c    | 98 +++++++++++++++++++++++++++++++++--------------
 kernel/features/syscall.c |  6 ++-
 kernel/inc/fs.h           |  3 ++
 kernel/inc/proc.h         | 16 +++++---
 kernel/main.c             |  3 +-
 9 files changed, 128 insertions(+), 50 deletions(-)

(limited to 'kernel')

diff --git a/kernel/drivers/ide.c b/kernel/drivers/ide.c
index 8fc90c9..9be7956 100644
--- a/kernel/drivers/ide.c
+++ b/kernel/drivers/ide.c
@@ -126,7 +126,7 @@ void ata_probe(void)
 		if (!ide_find(bus, drive))
 			continue;
 
-		struct device *dev = malloc(sizeof(*dev));
+		struct device *dev = zalloc(sizeof(*dev));
 		struct ata_data *data = malloc(sizeof(*data));
 		data->drive = (bus << 1) | drive;
 
@@ -144,7 +144,7 @@ void ata_probe(void)
 			continue;
 
 		// TODO: Check if ext2 first
-		struct vfs *vfs = malloc(sizeof(*vfs));
+		struct vfs *vfs = zalloc(sizeof(*vfs));
 		vfs->type = VFS_EXT2;
 		vfs->read = ext2_read;
 		vfs->stat = ext2_stat;
@@ -158,6 +158,6 @@ void ata_probe(void)
 
 void ata_install(void)
 {
-	ide_buf = malloc(SECTOR_SIZE);
+	ide_buf = zalloc(SECTOR_SIZE);
 	ata_probe();
 }
diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c
index 1652625..f22af80 100644
--- a/kernel/drivers/keyboard.c
+++ b/kernel/drivers/keyboard.c
@@ -33,8 +33,6 @@ void keyboard_handler()
 	// TODO: "Merge" scancode to linux keycode?
 	/* printf("%x %x = %x\n", scancode, state ? 0xe0 : 0, merged); */
 
-	if (event)
-		free(event);
 	event = malloc(sizeof(*event));
 	event->magic = KEYBOARD_MAGIC;
 	event->press = (scancode & 0x80) == 0;
@@ -68,6 +66,7 @@ s32 keyboard_read(void *buf, u32 offset, u32 count, struct device *dev)
 
 	struct event *e = stack_pop(queue);
 	memcpy(buf, (u8 *)e + offset, count);
+	free(e);
 	return count;
 }
 
@@ -87,7 +86,7 @@ void keyboard_install(void)
 	irq_install_handler(1, keyboard_handler);
 
 	queue = stack_new();
-	struct device *dev = malloc(sizeof(*dev));
+	struct device *dev = zalloc(sizeof(*dev));
 	dev->name = strdup("kbd");
 	dev->type = DEV_CHAR;
 	dev->read = keyboard_read;
diff --git a/kernel/drivers/mouse.c b/kernel/drivers/mouse.c
index 1e7fd1a..6f329aa 100644
--- a/kernel/drivers/mouse.c
+++ b/kernel/drivers/mouse.c
@@ -35,8 +35,6 @@ void mouse_handler()
 	case 2:
 		mouse_byte[2] = (char)inb(0x60);
 
-		if (event)
-			free(event);
 		event = malloc(sizeof(*event));
 		event->magic = MOUSE_MAGIC;
 		event->diff_x = mouse_byte[1];
@@ -96,6 +94,7 @@ s32 mouse_read(void *buf, u32 offset, u32 count, struct device *dev)
 
 	struct event *e = stack_pop(queue);
 	memcpy(buf, (u8 *)e + offset, count);
+	free(e);
 	return count;
 }
 
@@ -181,7 +180,7 @@ void mouse_install(void)
 	irq_install_handler(12, mouse_handler);
 
 	queue = stack_new();
-	struct device *dev = malloc(sizeof(*dev));
+	struct device *dev = zalloc(sizeof(*dev));
 	dev->name = strdup("mouse");
 	dev->type = DEV_CHAR;
 	dev->read = mouse_read;
diff --git a/kernel/features/fs.c b/kernel/features/fs.c
index 16a12f7..1744b51 100644
--- a/kernel/features/fs.c
+++ b/kernel/features/fs.c
@@ -120,10 +120,11 @@ s32 vfs_mount(struct device *dev, const char *path)
 
 s32 vfs_read(const char *path, void *buf, u32 offset, u32 count)
 {
+	/* printf("%s READ: %s\n", proc_current()->name, path); */
 	if (!count)
 		return 0;
 
-	if (offset > count)
+	if (offset > count || !buf)
 		return -1;
 
 	while (*path == ' ')
@@ -144,10 +145,11 @@ s32 vfs_read(const char *path, void *buf, u32 offset, u32 count)
 
 s32 vfs_write(const char *path, void *buf, u32 offset, u32 count)
 {
+	/* printf("%s WRITE: %s\n", proc_current()->name, path); */
 	if (!count)
 		return 0;
 
-	if (offset > count)
+	if (offset > count || !buf)
 		return -1;
 
 	while (*path == ' ')
@@ -171,6 +173,9 @@ s32 vfs_stat(const char *path, struct stat *buf)
 	while (*path == ' ')
 		path++;
 
+	if (!buf)
+		return -1;
+
 	struct mount_info *m = vfs_find_mount_info(path);
 	assert(m && m->dev && m->dev->vfs && m->dev->vfs->stat);
 
@@ -181,6 +186,27 @@ s32 vfs_stat(const char *path, struct stat *buf)
 	return m->dev->vfs->stat(path, buf, m->dev);
 }
 
+s32 vfs_wait(const char *path, s32 (*func)())
+{
+	while (*path == ' ')
+		path++;
+
+	struct mount_info *m = vfs_find_mount_info(path);
+	assert(m && m->dev && m->dev->vfs);
+
+	// Default wait
+	if (!m->dev->vfs->wait) {
+		proc_wait_for(vfs_find_dev(path)->id, PROC_WAIT_DEV, func);
+		return 1;
+	}
+
+	u32 len = strlen(m->path);
+	if (len > 1)
+		path += len;
+
+	return m->dev->vfs->wait(path, func, m->dev);
+}
+
 s32 vfs_poll(const char **files)
 {
 	if (!files)
@@ -191,7 +217,7 @@ s32 vfs_poll(const char **files)
 			return p - files;
 
 	for (const char **p = files; *p && **p; p++)
-		proc_wait_for(vfs_find_dev(*p)->id, PROC_WAIT_DEV, vfs_poll);
+		vfs_wait(*p, vfs_poll);
 
 	return PROC_MAX_WAIT_IDS + 1;
 }
@@ -280,12 +306,12 @@ void device_install(void)
 {
 	devices = list_new();
 
-	struct vfs *vfs = malloc(sizeof(*vfs));
+	struct vfs *vfs = zalloc(sizeof(*vfs));
 	vfs->type = VFS_DEVFS;
 	vfs->read = devfs_read;
 	vfs->perm = devfs_perm;
 	vfs->ready = devfs_ready;
-	struct device *dev = malloc(sizeof(*dev));
+	struct device *dev = zalloc(sizeof(*dev));
 	dev->name = "dev";
 	dev->type = DEV_CHAR;
 	dev->vfs = vfs;
diff --git a/kernel/features/proc.c b/kernel/features/proc.c
index 9c7fcdc..fdf509c 100644
--- a/kernel/features/proc.c
+++ b/kernel/features/proc.c
@@ -164,30 +164,27 @@ void proc_enable_waiting(u32 id, enum proc_wait_type type)
 		struct proc *p = iterator->data;
 		struct proc_wait *w = &p->wait;
 
-		if (!p || !w || w->id_cnt == 0 || w->type != type) {
+		if (!p || !w || w->id_cnt == 0) {
 			iterator = iterator->next;
 			continue;
 		}
 
-		u8 dispatched = 0;
-
 		current = list_first_data(proc_list, p);
-		for (u32 i = 0; i < PROC_MAX_WAIT_IDS; i++) {
-			if (w->ids[i] == id) {
+		assert(w->id_cnt < PROC_MAX_WAIT_IDS);
+		for (u32 i = 0; i < w->id_cnt; i++) {
+			if (w->ids[i].magic == PROC_WAIT_MAGIC && w->ids[i].id == id &&
+			    w->ids[i].type == type) {
 				struct regs *r = &p->regs;
-				if (w->func)
-					r->eax = (u32)w->func((char *)r->ebx, (void *)r->ecx,
-							      r->edx, r->esi);
-				w->ids[i] = 0;
+				if (w->ids[i].func)
+					r->eax = (u32)w->ids[i].func((char *)r->ebx, (void *)r->ecx,
+								     r->edx, r->esi);
+				memset(&w->ids[i], 0, sizeof(w->ids[i]));
+				p->wait.id_cnt--;
 				p->state = PROC_RUNNING;
-				dispatched = 1;
 				break;
 			}
 		}
 
-		if (dispatched)
-			memset(&p->wait, 0, sizeof(p->wait));
-
 		iterator = iterator->next;
 	}
 
@@ -197,25 +194,45 @@ void proc_enable_waiting(u32 id, enum proc_wait_type type)
 
 void proc_wait_for(u32 id, enum proc_wait_type type, s32 (*func)())
 {
+	u8 already_exists = 0;
 	struct proc *p = proc_current();
 
-	if (p->wait.id_cnt > 0) {
-		p->wait.ids[p->wait.id_cnt++] = id;
-		assert(func == p->wait.func && type == p->wait.type);
-	} else {
-		p->wait.type = type;
-		p->wait.id_cnt = 1;
-		p->wait.ids[0] = id;
-		p->wait.func = func;
+	// Check if already exists
+	for (u32 i = 0; i < p->wait.id_cnt; i++) {
+		if (p->wait.ids[i].id == id && p->wait.ids[i].type == type) {
+			assert(p->wait.ids[i].func == func);
+			already_exists = 1;
+		}
+	}
+
+	if (already_exists)
+		goto end;
+
+	assert(p->wait.id_cnt + 1 < PROC_MAX_WAIT_IDS);
+
+	// Find slot
+	struct proc_wait_identifier *slot = NULL;
+	for (u32 i = 0; i < PROC_MAX_WAIT_IDS; i++) {
+		if (p->wait.ids[i].magic != PROC_WAIT_MAGIC) {
+			slot = &p->wait.ids[i];
+			break;
+		}
 	}
+	assert(slot != NULL);
+
+	slot->magic = PROC_WAIT_MAGIC;
+	slot->id = id;
+	slot->type = type;
+	slot->func = func;
+	p->wait.id_cnt++;
 
+end:
 	p->state = PROC_SLEEPING;
 }
 
 struct proc *proc_make(void)
 {
-	struct proc *proc = malloc(sizeof(*proc));
-	memset(proc, 0, sizeof(*proc));
+	struct proc *proc = zalloc(sizeof(*proc));
 	proc->pid = current_pid++;
 	proc->super = 0;
 	proc->messages = stack_new();
@@ -274,7 +291,7 @@ s32 procfs_write(const char *path, void *buf, u32 offset, u32 count, struct devi
 		path++;
 		if (!memcmp(path, "msg", 4)) {
 			stack_push_bot(p->messages, buf); // TODO: Use offset and count
-			proc_enable_waiting(dev->id, PROC_WAIT_DEV); // TODO: Better wakeup solution
+			proc_enable_waiting(pid, PROC_WAIT_MSG);
 			return count;
 		} else if (!memcmp(path, "io/", 3)) {
 			path += 3;
@@ -324,10 +341,11 @@ s32 procfs_read(const char *path, void *buf, u32 offset, u32 count, struct devic
 			return count;
 		} else if (!memcmp(path, "msg", 4)) {
 			if (stack_empty(p->messages)) {
-				return 0;
+				return 0; // This shouldn't happen
 			} else {
 				u8 *msg = stack_pop(p->messages);
-				printf("Pop: %s\n", msg);
+				if (!msg)
+					return -1;
 				memcpy(buf, msg + offset, count);
 				return count;
 			}
@@ -346,6 +364,29 @@ s32 procfs_read(const char *path, void *buf, u32 offset, u32 count, struct devic
 	return -1;
 }
 
+s32 procfs_wait(const char *path, s32 (*func)(), struct device *dev)
+{
+	u32 pid = 0;
+	procfs_parse_path(&path, &pid);
+
+	if (pid) {
+		struct proc *p = proc_from_pid(pid);
+		if (!p || path[0] != '/')
+			return -1;
+
+		path++;
+		if (!memcmp(path, "msg", 4)) {
+			proc_wait_for(pid, PROC_WAIT_MSG, func);
+			return 1;
+		} else {
+			proc_wait_for(dev->id, PROC_WAIT_DEV, func);
+			return 1;
+		}
+	}
+
+	return -1;
+}
+
 u8 procfs_perm(const char *path, enum vfs_perm perm, struct device *dev)
 {
 	(void)path;
@@ -398,14 +439,15 @@ void proc_init(void)
 	proc_list = list_new();
 
 	// Procfs
-	struct vfs *vfs = malloc(sizeof(*vfs));
+	struct vfs *vfs = zalloc(sizeof(*vfs));
 	vfs->type = VFS_PROCFS;
 	vfs->read = procfs_read;
 	vfs->write = procfs_write;
+	vfs->wait = procfs_wait;
 	vfs->perm = procfs_perm;
 	vfs->ready = procfs_ready;
 	vfs->data = NULL;
-	struct device *dev = malloc(sizeof(*dev));
+	struct device *dev = zalloc(sizeof(*dev));
 	dev->name = "proc";
 	dev->type = DEV_CHAR;
 	dev->vfs = vfs;
diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c
index 80c3e9e..9f05471 100644
--- a/kernel/features/syscall.c
+++ b/kernel/features/syscall.c
@@ -40,8 +40,10 @@ void syscall_handler(struct regs *r)
 		if (vfs_ready((char *)r->ebx)) {
 			r->eax = (u32)vfs_read((char *)r->ebx, (void *)r->ecx, r->edx, r->esi);
 		} else {
-			proc_wait_for(vfs_find_dev((char *)r->ebx)->id, PROC_WAIT_DEV, vfs_read);
-			proc_yield(r);
+			if (vfs_wait((char *)r->ebx, vfs_read) < 0)
+				r->eax = -1;
+			else
+				proc_yield(r);
 		}
 		break;
 	}
diff --git a/kernel/inc/fs.h b/kernel/inc/fs.h
index 1f46ba3..868cd3e 100644
--- a/kernel/inc/fs.h
+++ b/kernel/inc/fs.h
@@ -41,6 +41,7 @@ struct vfs {
 	s32 (*read)(const char *path, void *buf, u32 offset, u32 count, struct device *dev);
 	s32 (*write)(const char *path, void *buf, u32 offset, u32 count, struct device *dev);
 	s32 (*stat)(const char *path, struct stat *buf, struct device *dev);
+	s32 (*wait)(const char *path, s32 (*func)(), struct device *dev);
 	u8 (*perm)(const char *path, enum vfs_perm perm, struct device *dev);
 	u8 (*ready)(const char *path, struct device *dev);
 };
@@ -60,10 +61,12 @@ struct device *vfs_find_dev(const char *path);
 s32 vfs_read(const char *path, void *buf, u32 offset, u32 count);
 s32 vfs_write(const char *path, void *buf, u32 offset, u32 count);
 s32 vfs_stat(const char *path, struct stat *buf);
+s32 vfs_wait(const char *path, s32 (*func)());
 s32 vfs_poll(const char **files);
 u8 vfs_ready(const char *path);
 
 struct device *device_get_by_name(const char *name);
+struct device *device_get_by_id(u32 id);
 
 /**
  * EXT2
diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h
index 593141b..cb583d6 100644
--- a/kernel/inc/proc.h
+++ b/kernel/inc/proc.h
@@ -17,21 +17,27 @@
 #define GDT_USER_CODE_OFFSET 0x1b // User code segment offset in GDT (with ring3 mask)
 #define GDT_USER_DATA_OFFSET 0x23 // User data segment offset in GDT (with ring3 mask)
 
-#define PROC_MAX_WAIT_IDS 16
+#define PROC_MAX_WAIT_IDS 128
+#define PROC_WAIT_MAGIC 0x00528491
 
 #define STREAM_MAX_SIZE 4096
 enum stream_defaults { STREAM_IN, STREAM_OUT, STREAM_ERR, STREAM_LOG, STREAM_UNKNOWN = -1 };
 
 enum proc_state { PROC_RUNNING, PROC_SLEEPING };
-enum proc_wait_type { PROC_WAIT_DEV };
+enum proc_wait_type { PROC_WAIT_DEV, PROC_WAIT_MSG };
 
-struct proc_wait {
+struct proc_wait_identifier {
+	u32 magic;
+	u32 id;
 	enum proc_wait_type type;
-	u32 ids[PROC_MAX_WAIT_IDS]; // dev_id
-	u32 id_cnt;
 	s32 (*func)();
 };
 
+struct proc_wait {
+	struct proc_wait_identifier ids[PROC_MAX_WAIT_IDS]; // dev_id
+	u32 id_cnt;
+};
+
 struct stream {
 	u32 offset_read;
 	u32 offset_write;
diff --git a/kernel/main.c b/kernel/main.c
index c20dee4..5216401 100644
--- a/kernel/main.c
+++ b/kernel/main.c
@@ -24,7 +24,8 @@ void kernel_main(struct vid_info *vid_info)
 
 	// Serial connection
 	serial_install();
-	serial_print("\nConnected.\n");
+	serial_print("\nKernel was compiled at " __TIME__ " on " __DATE__ "\n");
+	serial_print("Serial connected.\n");
 
 	cpu_print();
 
-- 
cgit v1.2.3