summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/execbuf.c1
-rw-r--r--src/kernel/main.c2
-rw-r--r--src/kernel/main.h1
-rw-r--r--src/kernel/proc.c108
-rw-r--r--src/kernel/proc.h39
-rw-r--r--src/kernel/syscalls.c12
6 files changed, 60 insertions, 103 deletions
diff --git a/src/kernel/execbuf.c b/src/kernel/execbuf.c
index 8ab0268..7170de2 100644
--- a/src/kernel/execbuf.c
+++ b/src/kernel/execbuf.c
@@ -1,4 +1,5 @@
#include <camellia/execbuf.h>
+#include <camellia/syscalls.h>
#include <kernel/execbuf.h>
#include <kernel/mem/alloc.h>
#include <kernel/panic.h>
diff --git a/src/kernel/main.c b/src/kernel/main.c
index 03ff177..ef7acee 100644
--- a/src/kernel/main.c
+++ b/src/kernel/main.c
@@ -7,7 +7,7 @@
void kmain(struct kmain_info info) {
kprintf("loading init...\n");
- process_seed(&info);
+ process_seed(info.init.at, info.init.size);
kprintf("switching...\n");
process_switch_any();
diff --git a/src/kernel/main.h b/src/kernel/main.h
index edceb76..45fd85e 100644
--- a/src/kernel/main.h
+++ b/src/kernel/main.h
@@ -14,5 +14,4 @@ struct kmain_info {
};
void kmain(struct kmain_info);
-
void shutdown(void);
diff --git a/src/kernel/proc.c b/src/kernel/proc.c
index fd02f33..2e765c7 100644
--- a/src/kernel/proc.c
+++ b/src/kernel/proc.c
@@ -1,21 +1,25 @@
-#include <camellia/syscalls.h>
#include <kernel/arch/generic.h>
#include <kernel/execbuf.h>
-#include <kernel/main.h>
#include <kernel/mem/alloc.h>
-#include <kernel/mem/virt.h>
#include <kernel/panic.h>
#include <kernel/proc.h>
#include <kernel/vfs/mount.h>
#include <shared/mem.h>
#include <stdint.h>
-struct process *process_first;
+static struct process *process_first = NULL;
struct process *process_current;
static uint32_t next_pid = 0;
-struct process *process_seed(struct kmain_info *info) {
+
+/** Removes a process from the process tree. */
+static void process_forget(struct process *p);
+static _Noreturn void process_switch(struct process *proc);
+
+
+struct process *process_seed(void *data, size_t datalen) {
+ assert(!process_first);
process_first = kmalloc(sizeof *process_first);
memset(process_first, 0, sizeof *process_first);
process_first->state = PS_RUNNING;
@@ -24,6 +28,7 @@ struct process *process_seed(struct kmain_info *info) {
process_first->id = next_pid++;
// map the stack to the last page in memory
+ // TODO move to user bootstrap
pagedir_map(process_first->pages, (userptr_t)~PAGE_MASK, page_zalloc(1), true, true);
process_first->regs.rsp = (userptr_t) ~0xF;
@@ -34,9 +39,8 @@ struct process *process_seed(struct kmain_info *info) {
// map the init module as rw
void __user *init_base = (userptr_t)0x200000;
- for (uintptr_t off = 0; off < info->init.size; off += PAGE_SIZE)
- pagedir_map(process_first->pages, init_base + off, info->init.at + off,
- true, true);
+ for (uintptr_t off = 0; off < datalen; off += PAGE_SIZE)
+ pagedir_map(process_first->pages, init_base + off, data + off, true, true);
process_first->regs.rcx = (uintptr_t)init_base; // SYSRET jumps to %rcx
return process_first;
@@ -164,34 +168,26 @@ void process_kill(struct process *p, int ret) {
if (p == process_first) shutdown();
}
-int process_try2collect(struct process *dead) {
- struct process *parent = dead->parent;
- int ret = -1;
-
+void process_try2collect(struct process *dead) {
assert(dead && dead->state == PS_DEAD);
+ assert(!dead->child);
- if (!dead->noreap && parent && parent->state != PS_DEAD) { // might be reaped
- if (parent->state != PS_WAITS4CHILDDEATH) return -1;
-
- ret = dead->death_msg;
- regs_savereturn(&parent->regs, ret);
+ struct process *parent = dead->parent;
+ if (!dead->noreap && parent && parent->state != PS_DEAD) { /* reapable? */
+ if (parent->state != PS_WAITS4CHILDDEATH)
+ return; /* don't reap yet */
+ regs_savereturn(&parent->regs, dead->death_msg);
process_transition(parent, PS_RUNNING);
}
- process_free(dead);
- return ret;
-}
-
-void process_free(struct process *p) {
- assert(p->state == PS_DEAD);
- assert(!p->child);
-
- if (!p->parent) return;
- process_forget(p);
- kfree(p);
+ if (dead != process_first) {
+ process_forget(dead);
+ kfree(dead);
+ }
}
-void process_forget(struct process *p) {
+/** Removes a process from the process tree. */
+static void process_forget(struct process *p) {
assert(p->parent);
if (p->parent->child == p) {
@@ -222,24 +218,26 @@ _Noreturn void process_switch_any(void) {
if (process_current && process_current->state == PS_RUNNING)
process_switch(process_current);
- struct process *found = process_find(PS_RUNNING);
- if (found) process_switch(found);
+ for (struct process *p = process_first; p; p = process_next(p)) {
+ if (p->state == PS_RUNNING)
+ process_switch(p);
+ }
cpu_pause();
}
}
struct process *process_next(struct process *p) {
- /* is a weird depth-first search, the search order is:
+ /* depth-first search, the order is:
* 1
* / \
* 2 5
* /| |\
* 3 4 6 7
*/
- if (!p) return NULL;
- if (p->child) return p->child;
- if (p->sibling) return p->sibling;
+ if (!p) return NULL;
+ if (p->child) return p->child;
+ if (p->sibling) return p->sibling;
/* looking at the diagram above - we're at 4, want to find 5 */
while (!p->sibling) {
@@ -249,22 +247,12 @@ struct process *process_next(struct process *p) {
return p->sibling;
}
-struct process *process_find(enum process_state target) {
- for (struct process *p = process_first; p; p = process_next(p)) {
- if (p->state == target) return p;
- }
- return NULL;
-}
-
handle_t process_find_free_handle(struct process *proc, handle_t start_at) {
- // TODO start_at is a bit of a hack
- handle_t handle;
- for (handle = start_at; handle < HANDLE_MAX; handle++) {
- if (proc->handles[handle] == NULL)
- break;
+ for (handle_t hid = start_at; hid < HANDLE_MAX; hid++) {
+ if (proc->handles[hid] == NULL)
+ return hid;
}
- if (handle >= HANDLE_MAX) handle = -1;
- return handle;
+ return -1;
}
struct handle *process_handle_get(struct process *p, handle_t id) {
@@ -273,24 +261,8 @@ struct handle *process_handle_get(struct process *p, handle_t id) {
}
void process_transition(struct process *p, enum process_state state) {
- enum process_state last = p->state;
+ assert(p->state != PS_DEAD);
+ if (state != PS_RUNNING && state != PS_DEAD)
+ assert(p->state == PS_RUNNING);
p->state = state;
- switch (state) {
- case PS_RUNNING:
- assert(last != PS_DEAD);
- break;
- case PS_DEAD:
- // see process_kill
- break;
- case PS_WAITS4CHILDDEATH:
- case PS_WAITS4FS:
- case PS_WAITS4REQUEST:
- case PS_WAITS4PIPE:
- case PS_WAITS4TIMER:
- assert(last == PS_RUNNING);
- break;
-
- case PS_LAST:
- panic_invalid_state();
- }
}
diff --git a/src/kernel/proc.h b/src/kernel/proc.h
index fb14e35..27327c4 100644
--- a/src/kernel/proc.h
+++ b/src/kernel/proc.h
@@ -1,10 +1,8 @@
#pragma once
-#include <camellia/syscalls.h>
#include <kernel/arch/generic.h>
#include <kernel/handle.h>
-#include <kernel/main.h>
-#include <kernel/vfs/mount.h>
#include <stdbool.h>
+struct vfs_mount;
#define HANDLE_MAX 16
@@ -23,18 +21,10 @@ enum process_state {
struct process {
struct pagedir *pages;
struct registers regs;
- enum process_state state;
-
- bool noreap;
-
- struct process *sibling;
- struct process *child;
- struct process *parent;
-
- uint32_t id; // only for debugging, don't expose to userland
+ struct process *sibling, *child, *parent;
- // saved value, meaning depends on .state
- union {
+ enum process_state state;
+ union { /* saved value, meaning depends on .state */
int death_msg; // PS_DEAD
struct {
char __user *buf;
@@ -53,38 +43,35 @@ struct process {
struct process *next;
} waits4timer;
};
- struct vfs_request *handled_req;
+
+ struct vfs_mount *mount;
+ struct handle *handles[HANDLE_MAX];
+ uint32_t id; /* only for debugging, don't expose to userland */
+ bool noreap;
/* allocated once, the requests from WAITS4FS get stored here */
struct vfs_request *reqslot;
/* vfs_backend controlled (not exclusively) by this process */
struct vfs_backend *controlled;
-
- struct vfs_mount *mount;
+ struct vfs_request *handled_req;
struct {
void *buf;
size_t len;
size_t pos;
} execbuf;
-
- struct handle *handles[HANDLE_MAX];
};
-extern struct process *process_first;
extern struct process *process_current;
/** Creates the root process. */
-struct process *process_seed(struct kmain_info *info);
+struct process *process_seed(void *data, size_t datalen);
struct process *process_fork(struct process *parent, int flags);
void process_kill(struct process *proc, int ret);
/** Tries to free a process / collect its return value. */
-int process_try2collect(struct process *dead);
-void process_free(struct process *);
-/** Removes a process from the process tree. */
-void process_forget(struct process *);
+void process_try2collect(struct process *dead);
/** Switches execution to any running process. */
_Noreturn void process_switch_any(void);
@@ -92,8 +79,6 @@ _Noreturn void process_switch_any(void);
/** Used for iterating over all processes */
struct process *process_next(struct process *);
-struct process *process_find(enum process_state);
-
handle_t process_find_free_handle(struct process *proc, handle_t start_at);
struct handle *process_handle_get(struct process *, handle_t);
diff --git a/src/kernel/syscalls.c b/src/kernel/syscalls.c
index 68c0241..6bdbf5f 100644
--- a/src/kernel/syscalls.c
+++ b/src/kernel/syscalls.c
@@ -13,9 +13,8 @@
#include <stdint.h>
#define SYSCALL_RETURN(val) do { \
- long ret = (long)val; \
assert(process_current->state == PS_RUNNING); \
- regs_savereturn(&process_current->regs, ret); \
+ regs_savereturn(&process_current->regs, (long)(val)); \
return 0; \
} while (0)
@@ -33,16 +32,17 @@ long _syscall_await(void) {
{
if (iter->noreap) continue;
has_children = true;
- if (iter->state == PS_DEAD)
- SYSCALL_RETURN(process_try2collect(iter));
+ if (iter->state == PS_DEAD) {
+ process_try2collect(iter);
+ return 0; // dummy
+ }
}
if (!has_children) {
process_transition(process_current, PS_RUNNING);
SYSCALL_RETURN(~0); // TODO errno
}
-
- return -1; // dummy
+ return 0; // dummy
}
long _syscall_fork(int flags, handle_t __user *fs_front) {