aboutsummaryrefslogtreecommitdiff
path: root/kernel/include/proc
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/include/proc')
-rw-r--r--kernel/include/proc/context.h62
-rw-r--r--kernel/include/proc/core.h15
-rw-r--r--kernel/include/proc/kmutex.h60
-rw-r--r--kernel/include/proc/kthread.h106
-rw-r--r--kernel/include/proc/proc.h200
-rw-r--r--kernel/include/proc/sched.h126
-rw-r--r--kernel/include/proc/spinlock.h37
7 files changed, 606 insertions, 0 deletions
diff --git a/kernel/include/proc/context.h b/kernel/include/proc/context.h
new file mode 100644
index 0000000..63c692e
--- /dev/null
+++ b/kernel/include/proc/context.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "types.h"
+
+#include "mm/pagetable.h"
+
+/*
+ * The function pointer to be implemented by functions which are entry
+ * points for new threads.
+ */
+typedef void *(*context_func_t)(long, void *);
+
+typedef struct context
+{
+ uintptr_t c_rip; /* instruction pointer (RIP) */
+ uintptr_t c_rsp; /* stack pointer (RSP) */
+ uintptr_t c_rbp; /* frame pointer (RBP) */
+
+ pml4_t
+ *c_pml4; /* pointer to the top level page table (PML4) for this proc.
+ It's the 'root' of the page table where virtual address -> physical address
+ lookup starts. */
+
+ uintptr_t c_kstack;
+ size_t c_kstacksz;
+} context_t;
+
+/**
+ * Initialize the given context such that when it begins execution it
+ * will execute func(arg1,arg2). A kernel stack and page directory
+ * exclusive to this context must also be provided.
+ *
+ * @param c the context to initialize
+ * @param func the function which will begin executing when this
+ * context is first made active
+ * @param arg1 the first argument to func
+ * @param arg2 the second argument to func
+ * @param kstack a pointer to the kernel stack this context will use
+ * @param kstacksz the size of the kernel stack
+ * @param pdptr the pagetable this context will use
+ */
+void context_setup(context_t *c, context_func_t func, long arg1, void *arg2,
+ void *kstack, size_t kstacksz, pml4_t *pml4);
+
+void context_setup_raw(context_t *c, void (*func)(), void *kstack,
+ size_t kstacksz, pml4_t *pml4);
+/**
+ * Makes the given context the one currently running on the CPU. Use
+ * this mainly for the initial context.
+ *
+ * @param c the context to make active
+ */
+void context_make_active(context_t *c);
+
+/**
+ * Save the current state of the machine into the old context, and begin
+ * executing the new context. Used primarily by the scheduler.
+ *
+ * @param oldc the context to switch from
+ * @param newc the context to switch to
+ */
+void context_switch(context_t *oldc, context_t *newc);
diff --git a/kernel/include/proc/core.h b/kernel/include/proc/core.h
new file mode 100644
index 0000000..9d6eb16
--- /dev/null
+++ b/kernel/include/proc/core.h
@@ -0,0 +1,15 @@
+#pragma once
+
+#include "proc/context.h"
+#include "proc/sched.h"
+#include "proc/spinlock.h"
+
+typedef struct core
+{
+ long kc_id;
+ context_t kc_ctx;
+
+ ktqueue_t *kc_queue;
+
+ uintptr_t kc_csdpaddr;
+} core_t;
diff --git a/kernel/include/proc/kmutex.h b/kernel/include/proc/kmutex.h
new file mode 100644
index 0000000..37d8ece
--- /dev/null
+++ b/kernel/include/proc/kmutex.h
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "proc/sched.h"
+#include "proc/spinlock.h"
+
+/*===========
+ * Structures
+ *==========*/
+
+typedef struct kmutex
+{
+ ktqueue_t km_waitq; /* wait queue */
+ struct kthread *km_holder; /* current holder */
+ list_link_t km_link;
+} kmutex_t;
+
+#define KMUTEX_INITIALIZER(mtx) \
+ { \
+ .km_waitq = KTQUEUE_INITIALIZER((mtx).km_waitq), .km_holder = NULL, \
+ .km_link = LIST_LINK_INITIALIZER((mtx).km_link), \
+ }
+
+/*==========
+ * Functions
+ *=========*/
+
+/**
+ * Initializes a mutex.
+ *
+ * @param mtx the mutex
+ */
+void kmutex_init(kmutex_t *mtx);
+
+/**
+ * Locks the specified mutex.
+ *
+ * Note: This function may block.
+ *
+ * Note: These locks are not re-entrant
+ *
+ * @param mtx the mutex to lock
+ */
+void kmutex_lock(kmutex_t *mtx);
+
+/**
+ * Unlocks the specified mutex.
+ *
+ * @param mtx the mutex to unlock
+ */
+void kmutex_unlock(kmutex_t *mtx);
+
+/**
+ * Indicates if a mutex has waiters.
+ */
+long kmutex_has_waiters(kmutex_t *mtx);
+
+/**
+ * Indicates if curthr owns a mutex.
+ */
+long kmutex_owns_mutex(kmutex_t *mtx);
diff --git a/kernel/include/proc/kthread.h b/kernel/include/proc/kthread.h
new file mode 100644
index 0000000..6bc66be
--- /dev/null
+++ b/kernel/include/proc/kthread.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#include <proc/context.h>
+#include <proc/sched.h>
+#include <proc/spinlock.h>
+#include <util/list.h>
+
+/*=====================
+ * Types and structures
+ *====================*/
+
+/*
+ * Alias for an entry point function of a new thread.
+ */
+typedef context_func_t kthread_func_t;
+
+/*
+ * Thread states.
+ */
+typedef enum
+{
+ KT_NO_STATE, /* Illegal state */
+ KT_ON_CPU, /* Currently running */
+ KT_RUNNABLE, /* On the run queue */
+ KT_SLEEP, /* Blocked indefinitely */
+ KT_SLEEP_CANCELLABLE, /* Blocked, but can be interrupted */
+ KT_EXITED /* Exited, waiting to be joined */
+} kthread_state_t;
+
+/*
+ * Thread descriptor.
+ */
+typedef struct kthread
+{
+ context_t kt_ctx; /* Thread context */
+ char *kt_kstack; /* Kernel stack */
+ void *kt_retval; /* Return value */
+ long kt_errno; /* Errno of most recent syscall */
+ struct proc *kt_proc; /* Corresponding process */
+
+ long kt_cancelled; /* Set if the thread has been cancelled */
+ ktqueue_t *kt_wchan; /* If blocking, the queue this thread is blocked on */
+ kthread_state_t kt_state;
+
+ list_link_t kt_plink; /* Link on the process's thread list, p_threads */
+ list_link_t
+ kt_qlink; /* Link on some ktqueue if the thread is not running */
+
+ list_t kt_mutexes; /* List of owned mutexes, for use in debugging */
+ long kt_recent_core; /* For SMP */
+
+ uint64_t kt_preemption_count;
+} kthread_t;
+
+/*==========
+ * Functions
+ *=========*/
+
+/**
+ * Initializes the kthread subsystem at system startup.
+ */
+void kthread_init(void);
+
+/**
+ * Allocates and initializes a kernel thread.
+ *
+ * @param proc the process in which the thread will run
+ * @param func the function that will be called when the newly created
+ * thread starts executing
+ * @param arg1 the first argument to func
+ * @param arg2 the second argument to func
+ * @return the newly created thread
+ *
+ */
+kthread_t *kthread_create(struct proc *proc, kthread_func_t func, long arg1,
+ void *arg2);
+
+/**
+ * Creates a clone of the specified thread
+ *
+ * @param thr the thread to clone
+ * @return a clone of thr
+ */
+kthread_t *kthread_clone(kthread_t *thr);
+
+/**
+ * Frees resources associated with a thread.
+ *
+ * @param thr the thread to free
+ */
+void kthread_destroy(kthread_t *thr);
+
+/**
+ * Cancels a thread.
+ *
+ * @param kthr the thread to be cancelled
+ * @param retval the return value for the thread
+ */
+void kthread_cancel(kthread_t *kthr, void *retval);
+
+/**
+ * Exits the current thread.
+ *
+ * @param retval the return value for the thread
+ */
+void kthread_exit(void *retval);
diff --git a/kernel/include/proc/proc.h b/kernel/include/proc/proc.h
new file mode 100644
index 0000000..bc608a0
--- /dev/null
+++ b/kernel/include/proc/proc.h
@@ -0,0 +1,200 @@
+#pragma once
+
+#include "config.h"
+#include "mm/pagetable.h"
+#include "proc/kthread.h"
+#include "types.h"
+#include "vm/vmmap.h"
+
+/*===========
+ * Structures
+ *==========*/
+
+/*
+ * Process resource information
+ */
+#define PROC_MAX_COUNT 65536
+#define PROC_NAME_LEN 256
+
+/* Process states */
+typedef enum
+{
+ PROC_RUNNING, /* Has running threads */
+ PROC_DEAD /* Exited, but not yet wait'ed */
+} proc_state_t;
+
+/* Process descriptor */
+typedef struct proc
+{
+ pid_t p_pid; /* Process ID */
+ char p_name[PROC_NAME_LEN]; /* Process name */
+
+ list_t p_threads; /* Threads list */
+ list_t p_children; /* Children list */
+ struct proc *p_pproc; /* Parent process */
+
+ list_link_t p_list_link; /* Link of list of all processes */
+ list_link_t p_child_link; /* Link on parent's list of children */
+
+ long p_status; /* Exit status */
+ proc_state_t p_state; /* Process state */
+
+ pml4_t *p_pml4; /* Page table. */
+
+ /*
+ * If a parent is waiting on a child, the parent puts itself on its own
+ * p_wait queue. When a child terminates, it broadcasts on its parent's
+ * p_wait to wake it up.
+ */
+ ktqueue_t p_wait;
+
+ /* VFS related */
+ struct file *p_files[NFILES]; /* Open files */
+ struct vnode *p_cwd; /* Current working directory */
+
+ /* VM related */
+ /*
+ * The current value of a process's break is maintained in the 'p_brk'.
+ *
+ * The 'p_brk' and 'p_start_brk' members of a proc_t struct are initialized
+ * by the loader. 'p_start_brk' is subsequently never modified; it always
+ * holds the initial value of the break.
+ *
+ * The loader sets 'p_start_brk' to be the end of the bss section (search
+ * online for memory layout diagrams of a running process for more
+ * details).
+ *
+ * These are both addresses.
+ */
+ void *p_brk; /* Process break; see brk(2) */
+ void *p_start_brk; /* Initial value of process break */
+ struct vmmap *p_vmmap; /* List of areas mapped into process's
+ user address space. */
+} proc_t;
+
+/*==========
+ * Functions
+ *=========*/
+
+/**
+ * Initializes the proc subsystem at system startup.
+ */
+void proc_init(void);
+
+/**
+ * Initializes the special idleproc at system startup.
+ */
+void proc_idleproc_init();
+
+/**
+ * Shuts down certain subsystems at system shutdown.
+ */
+void initproc_finish();
+
+/**
+ * Allocates and initializes a new process.
+ *
+ * @param name the name to give the newly created process
+ * @return the newly created process
+ */
+proc_t *proc_create(const char *name);
+
+/**
+ * Frees all the resources associated with a process.
+ *
+ * @param proc process to destroy
+ */
+void proc_destroy(proc_t *proc);
+
+/**
+ * Handles exiting the current process.
+ *
+ * @param retval exit code for the thread and process
+ */
+void proc_thread_exiting(void *retval);
+
+/**
+ * Stops another process from running again by cancelling all its
+ * threads.
+ *
+ * @param proc the process to kill
+ * @param status the status the process should exit with
+ */
+void proc_kill(proc_t *proc, long status);
+
+/**
+ * Kills every process except for the idle process and direct children
+ * of the idle process.
+ */
+void proc_kill_all(void);
+
+/*========================
+ * Functions: System calls
+ *=======================*/
+
+/**
+ * Implements the _exit(2) system call.
+ *
+ * @param status the exit status of the process
+ */
+void do_exit(long status);
+
+/**
+ * Implements the waitpid(2) system call.
+ *
+ * @param pid the pid to wait on, or -1 to wait on any child
+ * @param status used to return the exit status of the child
+ * @param options only 0 is supported (no options)
+ *
+ * @return the pid of the child process which was cleaned up, or
+ * - ENOTSUP invalid input
+ * - ECHILD valid child could not be found
+ */
+pid_t do_waitpid(pid_t pid, int *status, int options);
+
+/**
+ * This function implements the fork(2) system call.
+ *
+ * @param regs the register state at the time of the system call
+ */
+struct regs;
+long do_fork(struct regs *regs);
+
+/*===========
+ * Miscellany
+ *==========*/
+
+/*
+ * Special PIDs reserved for specific processes
+ */
+#define PID_IDLE 0
+#define PID_INIT 1
+
+/*
+ * Enable global use of idleproc
+ */
+extern proc_t idleproc;
+
+/*=====================
+ * Functions: Debugging
+ *====================*/
+
+/**
+ * Provides detailed debug information about a given process.
+ *
+ * @param arg a pointer to the process
+ * @param buf buffer to write to
+ * @param osize size of the buffer
+ * @return the remaining size of the buffer
+ */
+size_t proc_info(const void *arg, char *buf, size_t osize);
+
+/**
+ * Provides debug information overview of all processes.
+ *
+ * @param arg must be NULL
+ * @param buf buffer to write to
+ * @param osize size of the buffer
+ * @return the remaining size of the buffer
+ */
+size_t proc_list_info(const void *arg, char *buf, size_t osize); \ No newline at end of file
diff --git a/kernel/include/proc/sched.h b/kernel/include/proc/sched.h
new file mode 100644
index 0000000..343e8d5
--- /dev/null
+++ b/kernel/include/proc/sched.h
@@ -0,0 +1,126 @@
+#pragma once
+
+#include "proc/spinlock.h"
+#include "util/list.h"
+
+/*===========
+ * Structures
+ *==========*/
+
+/*
+ * Queue structure for kthreads
+ * Note that ktqueue functions are private - managing the queue
+ * should be done within sched.c, or using public functions
+ */
+typedef struct ktqueue
+{
+ list_t tq_list;
+ size_t tq_size;
+} ktqueue_t;
+
+/*
+ * Macro to initialize a ktqueue. See sched_queue_init for how the
+ * queue should be initialized in your code.
+ */
+#define KTQUEUE_INITIALIZER(ktqueue) \
+ { \
+ .tq_list = LIST_INITIALIZER((ktqueue).tq_list), \
+ }
+
+/*
+ * kthread declaration to make function signatures happy
+ */
+struct kthread;
+
+/*==========
+ * Functions
+ *=========*/
+
+/**
+ * Runs a new thread from the run queue.
+ *
+ * @param queue the queue to place curthr on
+ */
+void sched_switch(ktqueue_t *queue);
+
+/**
+ * Helps with context switching.
+ */
+void core_switch();
+
+/**
+ * Yields the CPU to another runnable thread.
+ */
+void sched_yield();
+
+/**
+ * Enables a thread to be selected by the scheduler to run.
+ *
+ * @param thr the thread to make runnable
+ */
+void sched_make_runnable(struct kthread *thr);
+
+/**
+ * Causes the current thread to enter into an uncancellable sleep on
+ * the given queue.
+ *
+ * @param q the queue to sleep on
+ * @param lock optional lock for release in another context
+ */
+void sched_sleep_on(ktqueue_t *q);
+
+/**
+ * Causes the current thread to enter into a cancellable sleep on the
+ * given queue.
+ *
+ * @param queue the queue to sleep on
+ * @param lock optional lock for release in another context
+ * @return -EINTR if the thread was cancelled and 0 otherwise
+ */
+long sched_cancellable_sleep_on(ktqueue_t *queue);
+
+/**
+ * Wakes up a thread from q.
+ *
+ * @param q queue
+ * @param thrp if an address is provided, *thrp is set to the woken up thread
+ *
+ */
+void sched_wakeup_on(ktqueue_t *q, struct kthread **thrp);
+
+/**
+ * Wake up all threads running on the queue.
+ *
+ * @param q the queue to wake up threads from
+ */
+void sched_broadcast_on(ktqueue_t *q);
+
+/**
+ * Cancel the given thread from the queue it sleeps on.
+ *
+ * @param the thread to cancel sleep from
+ */
+void sched_cancel(struct kthread *thr);
+
+/**
+ * Initializes a queue.
+ *
+ * @param queue the queue
+ */
+void sched_queue_init(ktqueue_t *queue);
+
+/**
+ * Returns true if the queue is empty.
+ *
+ * @param queue the queue
+ * @return true if the queue is empty
+ */
+long sched_queue_empty(ktqueue_t *queue);
+
+/**
+ * Functions for managing the current thread's preemption status.
+ */
+void preemption_disable();
+void preemption_enable();
+void preemption_reset();
+long preemption_enabled(); \ No newline at end of file
diff --git a/kernel/include/proc/spinlock.h b/kernel/include/proc/spinlock.h
new file mode 100644
index 0000000..4ce57c8
--- /dev/null
+++ b/kernel/include/proc/spinlock.h
@@ -0,0 +1,37 @@
+#pragma once
+
+typedef struct spinlock
+{
+ volatile char s_locked;
+} spinlock_t;
+
+#define SPINLOCK_INITIALIZER(lock) \
+ { \
+ .s_locked = 0 \
+ }
+
+/**
+ * Initializes the fields of the specified spinlock_t
+ * @param lock the spinlock to initialize
+ */
+void spinlock_init(spinlock_t *lock);
+
+/**
+ * Locks the specified spinlock.
+ *
+ * Note: this function may spin on the current core.
+ *
+ * Note: these locks are not re-entrant
+ *
+ * @param lock the spinlock to lock
+ */
+void spinlock_lock(spinlock_t *lock);
+
+/**
+ * Unlocks the specified spinlock.
+ *
+ * @param lock the spinlock to unlock
+ */
+void spinlock_unlock(spinlock_t *lock);
+
+long spinlock_ownslock(spinlock_t *lock);