summaryrefslogtreecommitdiff
path: root/src/kernel/task
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/task')
-rw-r--r--src/kernel/task/idt.c14
-rw-r--r--src/kernel/task/idt.h6
-rw-r--r--src/kernel/task/syscall.c2
-rw-r--r--src/kernel/task/syscall.h2
-rw-r--r--src/kernel/task/task.c55
-rw-r--r--src/kernel/task/task.h7
-rw-r--r--src/kernel/task/timer.c5
7 files changed, 71 insertions, 20 deletions
diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c
index 80f13db..887ebf7 100644
--- a/src/kernel/task/idt.c
+++ b/src/kernel/task/idt.c
@@ -67,6 +67,8 @@ struct idt_ptr idt_ptr;
static int_callback irq_handlers[16] = {0};
static struct thread* irq_wakeup[16] = {0};
+/* Called in idt_.asm when an exception fires (interrupt 0 to 31).
+ Tries to handle the exception, panics if fails. */
void idt_isrHandler(struct registers regs) {
if ((regs.int_no == 14 && paging_fault(&regs) != 0) || regs.int_no != 14) {
if (tasking_handleException(&regs) == 0) {
@@ -80,6 +82,8 @@ void idt_isrHandler(struct registers regs) {
}
}
+/* Called in idt_.asm when an IRQ fires (interrupt 32 to 47)
+ Possibly wakes up a thread that was waiting, possibly calls a handler. */
void idt_irqHandler(struct registers regs) {
uint32_t doSwitch = (regs.err_code == 0); //IRQ0 = timer
if (regs.err_code > 7) {
@@ -97,14 +101,15 @@ void idt_irqHandler(struct registers regs) {
if (doSwitch) tasking_switch();
}
+/* Called in idt_.asm on a system call (interrupt 64).
+ Calls the correct syscall handler (if any). */
void idt_syscallHandler(struct registers regs) {
- if (syscalls[regs.eax] != 0) {
+ if (regs.eax < NUMBER_OF_SYSCALLS && syscalls[regs.eax] != 0) {
syscalls[regs.eax](&regs);
- } else {
- monitor_write("Unhandled syscall...\n");
}
}
+/* For internal use only. Sets up an entry of the IDT with given parameters. */
static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) {
idt_entries[num].base_lo = base & 0xFFFF;
idt_entries[num].base_hi = (base >> 16) & 0xFFFF;
@@ -114,6 +119,7 @@ static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags)
idt_entries[num].flags = flags | 0x60;
}
+/* Remaps the IRQs. Sets up the IDT. */
void idt_init() {
idt_ptr.limit = (sizeof(struct idt_entry) * 256) - 1;
idt_ptr.base = (uint32_t)&idt_entries;
@@ -189,12 +195,14 @@ void idt_init() {
monitor_write("[IDT] ");
}
+/* Sets up an IRQ handler for given IRQ. */
void idt_handleIrq(int number, int_callback func) {
if (number < 16 && number >= 0) {
irq_handlers[number] = func;
}
}
+/* Tells the IRQ handler to wake up the current thread when specified IRQ fires. */
void idt_waitIrq(int number) {
if (number < 16 && number >= 0 && proc_priv() <= PL_DRIVER) {
irq_wakeup[number] = current_thread;
diff --git a/src/kernel/task/idt.h b/src/kernel/task/idt.h
index b12d6c5..1ac03e2 100644
--- a/src/kernel/task/idt.h
+++ b/src/kernel/task/idt.h
@@ -1,6 +1,12 @@
#ifndef DEF_IDT_H
#define DEF_IDT_H
+/* The IDT is the system descriptor table that tells the CPU what to do when an interrupt fires.
+ There are three categories of interrupts :
+ - Exceptions ; ex: page fault, divide by 0
+ - IRQ : interrupts caused by hardware
+ - System calls : when an applications asks the system to do something */
+
#include <types.h>
struct idt_entry {
diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c
index a5142eb..41cd0ea 100644
--- a/src/kernel/task/syscall.c
+++ b/src/kernel/task/syscall.c
@@ -38,7 +38,7 @@ static void thread_new_sc(struct registers* r) {
thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx);
}
-int_callback syscalls[] = {
+int_callback syscalls[NUMBER_OF_SYSCALLS] = {
thread_exit_sc, //0
schedule_sc,
thread_sleep_sc,
diff --git a/src/kernel/task/syscall.h b/src/kernel/task/syscall.h
index 54af108..f03be55 100644
--- a/src/kernel/task/syscall.h
+++ b/src/kernel/task/syscall.h
@@ -3,6 +3,8 @@
#include "idt.h"
+#define NUMBER_OF_SYSCALLS 32
+
extern int_callback syscalls[];
#endif
diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c
index 8afc609..d8670a0 100644
--- a/src/kernel/task/task.c
+++ b/src/kernel/task/task.c
@@ -17,19 +17,20 @@ static void thread_exit2(uint32_t reason);
static void thread_delete(struct thread *th);
static void process_delete(struct process *pr);
+static uint32_t thread_runnable(struct thread *th);
+
//From task_.asm
extern uint32_t read_eip();
extern void task_idle(void*);
-static uint32_t thread_runnable(struct thread *th);
-
static uint32_t nextpid = 1;
-
struct process *processes = 0, *kernel_process;
struct thread *threads = 0, *current_thread = 0, *idle_thread;
uint32_t tasking_tmpStack[KSTACKSIZE];
+/* Sets up tasking. Called by kmain on startup.
+ Creates a kernel process and an IDLE thread in it. */
void tasking_init() {
cli();
kernel_process = kmalloc(sizeof(struct process)); //This process must be hidden to users
@@ -45,6 +46,19 @@ void tasking_init() {
monitor_write("[Tasking] ");
}
+/* Called by the paging functions when a page table is allocated in the kernel space (>0xE0000000).
+ Updates the page directories of all the processes. */
+void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablephysical) {
+ if (idx < 896) return;
+ struct process* it = processes;
+ while (it != 0) {
+ it->pagedir->tables[idx] = table;
+ it->pagedir->tablesPhysical[idx] = tablephysical;
+ it = it->next;
+ }
+}
+
+/* Looks through the list of threads, finds the next thread to run. */
static struct thread *thread_next() {
if (current_thread == 0 || current_thread == idle_thread) current_thread = threads;
struct thread *ret = current_thread;
@@ -60,6 +74,7 @@ static struct thread *thread_next() {
}
}
+/* Called when a timer IRQ fires. Does a context switch. */
void tasking_switch() {
if (threads == 0) PANIC("No more threads to run !");
asm volatile("cli");
@@ -94,16 +109,8 @@ void tasking_switch() {
: : "r"(current_thread->ebp), "r"(current_thread->esp), "r"(current_thread->eip));
}
-void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablephysical) {
- if (idx < 896) return;
- struct process* it = processes;
- while (it != 0) {
- it->pagedir->tables[idx] = table;
- it->pagedir->tablesPhysical[idx] = tablephysical;
- it = it->next;
- }
-}
-
+/* Called when an exception happens. Provides a stack trace if it was in kernel land.
+ Ends the thread for most exceptions, ends the whole process for page faults. */
uint32_t tasking_handleException(struct registers *regs) {
if (current_thread == 0) return 0; //No tasking yet
NL; WHERE; monitor_write("Unhandled exception : ");
@@ -134,6 +141,7 @@ uint32_t tasking_handleException(struct registers *regs) {
return 0;
}
+/* Makes the current thread sleep. */
void thread_sleep(uint32_t msecs) {
if (current_thread == 0) return;
current_thread->state = TS_SLEEPING;
@@ -141,20 +149,25 @@ void thread_sleep(uint32_t msecs) {
tasking_switch();
}
+/* Puts the current thread in an inactive state. */
void thread_goInactive() {
current_thread->state = TS_WAKEWAIT;
tasking_switch();
}
+/* Wakes up the given thread. */
void thread_wakeUp(struct thread* t) {
if (t->state == TS_WAKEWAIT) t->state = TS_RUNNING;
}
+/* Returns the privilege level of the current process. */
int proc_priv() {
if (current_thread == 0 || current_thread->process == 0) return PL_UNKNOWN;
return current_thread->process->privilege;
}
+/* For internal use only. Called by thread_exit_stackJmp on a stack that will not be deleted.
+ Exits current thread or process, depending on the reason. */
void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h
/*
* if reason == EX_TH_NORMAL, it is just one thread exiting because it has to
@@ -170,9 +183,12 @@ void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h
process_delete(pr);
}
retrn:
+ sti();
tasking_switch();
}
+/* For internal use only. Called by thread_exit and process_exit.
+ Switches to a stack that will not be deleted when current thread is deleted. */
void thread_exit_stackJmp(uint32_t reason) {
cli();
uint32_t *stack;
@@ -188,15 +204,18 @@ void thread_exit_stackJmp(uint32_t reason) {
"r"(stack), "r"(stack), "r"(thread_exit2), "r"(kernel_pagedir->physicalAddr));
}
+/* System call. Exit the current thread. */
void thread_exit() {
thread_exit_stackJmp(EX_TH_NORMAL);
}
+/* System call. Exit the current process. */
void process_exit(uint32_t retval) {
if (retval == EX_TH_NORMAL || retval == EX_TH_EXCEPTION) retval = EX_PR_EXCEPTION;
thread_exit_stackJmp(retval);
}
+/* Nonzero if given thread is not in a waiting state. */
static uint32_t thread_runnable(struct thread *t) {
if (t->state == TS_RUNNING) return 1;
if (t->state == TS_SLEEPING && timer_time() >= t->timeWait) {
@@ -206,6 +225,9 @@ static uint32_t thread_runnable(struct thread *t) {
return 0;
}
+/* For internal use only. This is called when a newly created thread first runs
+ (its address is the value given for EIP).
+ It switches to user mode if necessary and calls the entry point. */
static void thread_run(struct thread *thread, thread_entry entry_point, void *data) {
pagedir_switch(thread->process->pagedir);
if (thread->process->privilege >= PL_SERVICE) { //User mode !
@@ -248,6 +270,9 @@ static void thread_run(struct thread *thread, thread_entry entry_point, void *da
thread_exit(0);
}
+/* Creates a new thread for given process.
+ Allocates a kernel stack and a user stack if necessary.
+ Sets up the kernel stack for values to be passed to thread_run. */
struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data) {
struct thread *t = kmalloc(sizeof(struct thread));
t->process = proc;
@@ -284,6 +309,7 @@ struct thread *thread_new(struct process *proc, thread_entry entry_point, void *
return t;
}
+/* Creates a new process. Creates a struct process and fills it up. */
struct process *process_new(struct process* parent, uint32_t uid, uint32_t privilege) {
struct process* p = kmalloc(sizeof(struct process));
p->pid = (nextpid++);
@@ -307,6 +333,7 @@ struct process *process_new(struct process* parent, uint32_t uid, uint32_t privi
return p;
}
+/* Deletes given thread, freeing the stack(s). */
static void thread_delete(struct thread *th) {
if (threads == th) {
threads = th->next;
@@ -327,6 +354,7 @@ static void thread_delete(struct thread *th) {
kfree(th);
}
+/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */
static void process_delete(struct process *pr) {
struct thread *it = threads;
while (it != 0) {
@@ -354,6 +382,7 @@ static void process_delete(struct process *pr) {
kfree(pr);
}
+/* System call. Called by the app to define the place for the heap. */
int process_setheapseg(size_t start, size_t end) { //syscall
struct process *p = current_thread->process;
if (start >= 0xE0000000 || end >= 0xE0000000) return -1;
diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h
index 3dad63d..ef93c9f 100644
--- a/src/kernel/task/task.h
+++ b/src/kernel/task/task.h
@@ -57,13 +57,14 @@ void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint3
uint32_t tasking_handleException(struct registers *regs);
void thread_sleep(uint32_t msecs);
-void thread_goInactive(); //Blocks the current thread. another one must be there to wake it up at some point.
+void thread_goInactive(); //Blocks the current thread. it is then waked up by another thread or a system event.
void thread_wakeUp(struct thread *t);
int proc_priv(); //Returns current privilege level
-void thread_exit();
-void process_exit(uint32_t retval);
struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data);
struct process* process_new(struct process *parent, uint32_t uid, uint32_t privilege);
+
+void thread_exit(); //syscall
+void process_exit(uint32_t retval); //syscall
int process_setheapseg(size_t start, size_t end); //syscall
#endif
diff --git a/src/kernel/task/timer.c b/src/kernel/task/timer.c
index e924657..1ec1523 100644
--- a/src/kernel/task/timer.c
+++ b/src/kernel/task/timer.c
@@ -5,6 +5,8 @@
static uint32_t tick = 0, frequency = 0, uptime = 0;
+/* Called when IRQ0 fires. Updates the uptime variable.
+ DOES NOT provoke a task switch. The task switch is called in idt.c (IRQ handler). */
void timer_callback(struct registers *regs) {
tick++;
if (tick == frequency) {
@@ -13,12 +15,15 @@ void timer_callback(struct registers *regs) {
}
}
+/* Accessor function to get machine uptime. */
uint32_t timer_uptime() { return uptime; }
+/* Accessor function, gets uptime in miliseconds. */
uint32_t timer_time() {
return (uptime * 1000) + (tick * 1000 / frequency);
}
+/* Called by kmain. Sets up the PIT and the IRQ0 handler. */
void timer_init(uint32_t freq) {
frequency = freq;