summaryrefslogtreecommitdiff
path: root/src/kernel/task
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/task')
-rw-r--r--src/kernel/task/idt.c191
-rw-r--r--src/kernel/task/idt.h33
-rw-r--r--src/kernel/task/idt_.asm155
-rw-r--r--src/kernel/task/syscall.c21
-rw-r--r--src/kernel/task/syscall.h9
-rw-r--r--src/kernel/task/task.c245
-rw-r--r--src/kernel/task/task.h55
-rw-r--r--src/kernel/task/task_.asm10
-rw-r--r--src/kernel/task/timer.c36
-rw-r--r--src/kernel/task/timer.h10
10 files changed, 765 insertions, 0 deletions
diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c
new file mode 100644
index 0000000..360ac91
--- /dev/null
+++ b/src/kernel/task/idt.c
@@ -0,0 +1,191 @@
+#include "idt.h"
+#include <core/monitor.h>
+#include <core/sys.h>
+#include <mem/paging.h>
+#include "task.h"
+#include "syscall.h"
+
+#include <stdlib.h>
+
+extern void isr0();
+extern void isr1();
+extern void isr2();
+extern void isr3();
+extern void isr4();
+extern void isr5();
+extern void isr6();
+extern void isr7();
+extern void isr8();
+extern void isr9();
+extern void isr10();
+extern void isr11();
+extern void isr12();
+extern void isr13();
+extern void isr14();
+extern void isr15();
+extern void isr16();
+extern void isr17();
+extern void isr18();
+extern void isr19();
+extern void isr20();
+extern void isr21();
+extern void isr22();
+extern void isr23();
+extern void isr24();
+extern void isr25();
+extern void isr26();
+extern void isr27();
+extern void isr28();
+extern void isr29();
+extern void isr30();
+extern void isr31();
+
+extern void irq0();
+extern void irq1();
+extern void irq2();
+extern void irq3();
+extern void irq4();
+extern void irq5();
+extern void irq6();
+extern void irq7();
+extern void irq8();
+extern void irq9();
+extern void irq10();
+extern void irq11();
+extern void irq12();
+extern void irq13();
+extern void irq14();
+extern void irq15();
+
+extern void syscall64();
+
+extern void idt_flush(int32_t ptr);
+
+struct idt_entry idt_entries[256];
+struct idt_ptr idt_ptr;
+
+static int_callback irq_handlers[16] = {0};
+
+void idt_isrHandler(struct registers regs) {
+ if ((regs.int_no == 14 && paging_fault(&regs) != 0) || regs.int_no != 14) {
+ if (tasking_handleException(&regs) == 0) {
+ monitor_write(" >> >> SOMETHING BAD HAPPENNED << <<\n");
+ monitor_write("Unhandled exception ");
+ monitor_writeHex(regs.int_no);
+ monitor_write(" @"); monitor_writeHex(regs.eip);
+ monitor_put('\n');
+ PANIC("unhandled exception");
+ }
+ }
+}
+
+void idt_irqHandler(struct registers regs) {
+ uint32_t doSwitch = 0;
+ doSwitch |= (regs.int_no == 32); //IRQ0 = timer
+ if (regs.err_code > 7) {
+ outb(0xA0, 0x20);
+ }
+ outb(0x20, 0x20);
+ if (irq_handlers[regs.err_code] != 0) {
+ irq_handlers[regs.err_code](&regs);
+ } else {
+ monitor_write("Unhandled IRQ "); monitor_writeHex(regs.int_no - 32); monitor_write("\n");
+ }
+ if (doSwitch) tasking_switch();
+}
+
+void idt_syscallHandler(struct registers regs) {
+ if (syscalls[regs.eax] != 0) {
+ syscalls[regs.eax](&regs);
+ } else {
+ PANIC("unhandled syscall");
+ }
+}
+
+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;
+
+ idt_entries[num].sel = sel;
+ idt_entries[num].always0 = 0;
+ idt_entries[num].flags = flags;
+}
+
+void idt_init() {
+ idt_ptr.limit = (sizeof(struct idt_entry) * 256) - 1;
+ idt_ptr.base = (uint32_t)&idt_entries;
+
+ memset((uint8_t*)&idt_entries, 0, sizeof(struct idt_entry) * 256);
+
+ //Remap the IRQ table
+ outb(0x20, 0x11);
+ outb(0xA0, 0x11);
+ outb(0x21, 0x20);
+ outb(0xA1, 0x28);
+ outb(0x21, 0x04);
+ outb(0xA1, 0x02);
+ outb(0x21, 0x01);
+ outb(0xA1, 0x01);
+ outb(0x21, 0x0);
+ outb(0xA1, 0x0);
+
+ idt_setGate(0, (int32_t)isr0, 0x08, 0x8E);
+ idt_setGate(1, (int32_t)isr1, 0x08, 0x8E);
+ idt_setGate(2, (int32_t)isr2, 0x08, 0x8E);
+ idt_setGate(3, (int32_t)isr3, 0x08, 0x8E);
+ idt_setGate(4, (int32_t)isr4, 0x08, 0x8E);
+ idt_setGate(5, (int32_t)isr5, 0x08, 0x8E);
+ idt_setGate(6, (int32_t)isr6, 0x08, 0x8E);
+ idt_setGate(7, (int32_t)isr7, 0x08, 0x8E);
+ idt_setGate(8, (int32_t)isr8, 0x08, 0x8E);
+ idt_setGate(9, (int32_t)isr9, 0x08, 0x8E);
+ idt_setGate(10, (int32_t)isr10, 0x08, 0x8E);
+ idt_setGate(11, (int32_t)isr11, 0x08, 0x8E);
+ idt_setGate(12, (int32_t)isr12, 0x08, 0x8E);
+ idt_setGate(13, (int32_t)isr13, 0x08, 0x8E);
+ idt_setGate(14, (int32_t)isr14, 0x08, 0x8E);
+ idt_setGate(15, (int32_t)isr15, 0x08, 0x8E);
+ idt_setGate(16, (int32_t)isr16, 0x08, 0x8E);
+ idt_setGate(17, (int32_t)isr17, 0x08, 0x8E);
+ idt_setGate(18, (int32_t)isr18, 0x08, 0x8E);
+ idt_setGate(19, (int32_t)isr19, 0x08, 0x8E);
+ idt_setGate(20, (int32_t)isr20, 0x08, 0x8E);
+ idt_setGate(21, (int32_t)isr21, 0x08, 0x8E);
+ idt_setGate(22, (int32_t)isr22, 0x08, 0x8E);
+ idt_setGate(23, (int32_t)isr23, 0x08, 0x8E);
+ idt_setGate(24, (int32_t)isr24, 0x08, 0x8E);
+ idt_setGate(25, (int32_t)isr25, 0x08, 0x8E);
+ idt_setGate(26, (int32_t)isr26, 0x08, 0x8E);
+ idt_setGate(27, (int32_t)isr27, 0x08, 0x8E);
+ idt_setGate(28, (int32_t)isr28, 0x08, 0x8E);
+ idt_setGate(29, (int32_t)isr29, 0x08, 0x8E);
+ idt_setGate(30, (int32_t)isr30, 0x08, 0x8E);
+ idt_setGate(31, (int32_t)isr31, 0x08, 0x8E);
+
+ idt_setGate(32, (int32_t)irq0, 0x08, 0x8E);
+ idt_setGate(33, (int32_t)irq1, 0x08, 0x8E);
+ idt_setGate(34, (int32_t)irq2, 0x08, 0x8E);
+ idt_setGate(35, (int32_t)irq3, 0x08, 0x8E);
+ idt_setGate(36, (int32_t)irq4, 0x08, 0x8E);
+ idt_setGate(37, (int32_t)irq5, 0x08, 0x8E);
+ idt_setGate(38, (int32_t)irq6, 0x08, 0x8E);
+ idt_setGate(39, (int32_t)irq7, 0x08, 0x8E);
+ idt_setGate(40, (int32_t)irq8, 0x08, 0x8E);
+ idt_setGate(41, (int32_t)irq9, 0x08, 0x8E);
+ idt_setGate(42, (int32_t)irq10, 0x08, 0x8E);
+ idt_setGate(43, (int32_t)irq11, 0x08, 0x8E);
+ idt_setGate(44, (int32_t)irq12, 0x08, 0x8E);
+ idt_setGate(45, (int32_t)irq13, 0x08, 0x8E);
+ idt_setGate(46, (int32_t)irq14, 0x08, 0x8E);
+ idt_setGate(47, (int32_t)irq15, 0x08, 0x8E);
+
+ idt_setGate(64, (int32_t)syscall64, 0x08, 0x8E);
+
+ idt_flush((int32_t)&idt_ptr);
+
+ monitor_write("IDT ok\n");
+}
+
+void idt_handleIrq(int number, int_callback func) {
+ irq_handlers[number] = func;
+}
diff --git a/src/kernel/task/idt.h b/src/kernel/task/idt.h
new file mode 100644
index 0000000..bb89013
--- /dev/null
+++ b/src/kernel/task/idt.h
@@ -0,0 +1,33 @@
+#ifndef DEF_IDT_H
+#define DEF_IDT_H
+
+#include <types.h>
+
+struct idt_entry {
+ uint16_t base_lo; //Low part of address to jump to
+ uint16_t sel; //Kernel segment selector
+ uint8_t always0;
+ uint8_t flags; //Flags
+ uint16_t base_hi; //High part of address to jump to
+} __attribute__((packed));
+
+struct idt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+struct registers {
+ uint32_t cr3; //page directory physical address
+ uint32_t ds; // Data segment selector
+ uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; // Pushed by pusha.
+ uint32_t int_no, err_code; // Interrupt number and error code (if applicable)
+ uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically.
+};
+
+typedef void (*int_callback)(struct registers*);
+
+void idt_init();
+void idt_handleIrq(int number, int_callback func);
+
+#endif
+
diff --git a/src/kernel/task/idt_.asm b/src/kernel/task/idt_.asm
new file mode 100644
index 0000000..63d1570
--- /dev/null
+++ b/src/kernel/task/idt_.asm
@@ -0,0 +1,155 @@
+; UNRELATED
+
+[GLOBAL gdt_flush]
+
+gdt_flush:
+ mov eax, [esp+4]
+ lgdt [eax]
+
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ mov ss, ax
+ jmp 0x08:.flush
+
+.flush:
+ ret
+
+; RELATED
+
+[GLOBAL idt_flush]
+idt_flush:
+ mov eax, [esp+4] ; Get the pointer to the IDT, passed as a parameter.
+ lidt [eax] ; Load the IDT pointer.
+ ret
+
+;************************************************************************************
+
+%macro COMMONSTUB 1
+[EXTERN idt_%1Handler]
+%1_common_stub:
+ pusha ; Pushes edi,esi,ebp,esp,ebx,edx,ecx,eax
+
+ mov ax, ds ; Lower 16-bits of eax = ds.
+ push eax ; save the data segment descriptor
+
+ mov ax, 0x10 ; load the kernel data segment descriptor
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov eax, cr3
+ push eax
+
+ call idt_%1Handler
+
+ pop eax
+ mov cr3, eax
+
+ pop eax ; reload the original data segment descriptor
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+
+ popa ; Pops edi,esi,ebp...
+ add esp, 8 ; Cleans up the pushed error code and pushed ISR number
+ sti
+ iret
+%endmacro
+
+COMMONSTUB isr
+COMMONSTUB irq
+COMMONSTUB syscall
+
+;************************************************************************************
+
+%macro ISR_NOERRCODE 1 ; define a macro, taking one parameter
+ [GLOBAL isr%1] ; %1 accesses the first parameter.
+ isr%1:
+ cli
+ push byte 0
+ push byte %1
+ jmp isr_common_stub
+%endmacro
+
+%macro ISR_ERRCODE 1
+ [GLOBAL isr%1]
+ isr%1:
+ cli
+ push byte %1
+ jmp isr_common_stub
+%endmacro
+
+%macro IRQ 2
+ [GLOBAL irq%1]
+ irq%1:
+ cli
+ push byte %1 ;push irq number
+ push byte %2 ;push int number
+ jmp irq_common_stub
+%endmacro
+
+%macro SYSCALL 1
+ [GLOBAL syscall%1]
+ syscall%1:
+ cli
+ push byte 0
+ push byte %1
+ jmp syscall_common_stub
+%endmacro
+
+ISR_NOERRCODE 0
+ISR_NOERRCODE 1
+ISR_NOERRCODE 2
+ISR_NOERRCODE 3
+ISR_NOERRCODE 4
+ISR_NOERRCODE 5
+ISR_NOERRCODE 6
+ISR_NOERRCODE 7
+ISR_ERRCODE 8
+ISR_NOERRCODE 9
+ISR_ERRCODE 10
+ISR_ERRCODE 11
+ISR_ERRCODE 12
+ISR_ERRCODE 13
+ISR_ERRCODE 14
+ISR_NOERRCODE 15
+ISR_NOERRCODE 16
+ISR_NOERRCODE 17
+ISR_NOERRCODE 18
+ISR_NOERRCODE 19
+ISR_NOERRCODE 20
+ISR_NOERRCODE 21
+ISR_NOERRCODE 22
+ISR_NOERRCODE 23
+ISR_NOERRCODE 24
+ISR_NOERRCODE 25
+ISR_NOERRCODE 26
+ISR_NOERRCODE 27
+ISR_NOERRCODE 28
+ISR_NOERRCODE 29
+ISR_NOERRCODE 30
+ISR_NOERRCODE 31
+
+IRQ 0, 32
+IRQ 1, 33
+IRQ 2, 34
+IRQ 3, 35
+IRQ 4, 36
+IRQ 5, 37
+IRQ 6, 38
+IRQ 7, 39
+IRQ 8, 40
+IRQ 9, 41
+IRQ 10, 42
+IRQ 11, 43
+IRQ 12, 44
+IRQ 13, 45
+IRQ 14, 46
+IRQ 15, 47
+
+SYSCALL 64
diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c
new file mode 100644
index 0000000..5aab011
--- /dev/null
+++ b/src/kernel/task/syscall.c
@@ -0,0 +1,21 @@
+#include "syscall.h"
+
+#define CALL0(name, scname) static void scname(struct registers* r) { r->eax = name(); }
+#define CALL1(name, scname) static void scname(struct registers* r) { \
+ r->eax = name(r->ebx); }
+#define CALL2(name, scname) static void scname(struct registers* r) { \
+ r->eax = name(r->ebx, r->ecx); }
+
+CALL0(thread_exit, thread_exit_sc);
+CALL0(tasking_switch, schedule_sc);
+CALL1(thread_sleep, thread_sleep_sc);
+CALL1(process_exit, process_exit_sc);
+CALL1(monitor_write, printk_sc);
+
+int_callback syscalls[] = {
+ thread_exit_sc,
+ schedule_sc,
+ thread_sleep_sc,
+ process_exit_sc,
+ printk_sc,
+ 0 };
diff --git a/src/kernel/task/syscall.h b/src/kernel/task/syscall.h
new file mode 100644
index 0000000..54af108
--- /dev/null
+++ b/src/kernel/task/syscall.h
@@ -0,0 +1,9 @@
+#ifndef DEF_SYSCALL_H
+#define DEF_SYSCALL_H
+
+#include "idt.h"
+
+extern int_callback syscalls[];
+
+#endif
+
diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c
new file mode 100644
index 0000000..804adc2
--- /dev/null
+++ b/src/kernel/task/task.c
@@ -0,0 +1,245 @@
+#include "task.h"
+#include <core/sys.h>
+#include <core/monitor.h>
+#include <mem/mem.h>
+#include "timer.h"
+
+#define KSTACKSIZE 0x8000
+
+//Static routines for handling threads exiting and all cleanup
+static void thread_exit_stackJmp(uint32_t reason);
+static void thread_exit2(uint32_t reason);
+static void thread_delete(struct thread *th);
+static void process_delete(struct process *pr);
+
+//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[0x4000];
+
+void tasking_init() {
+ cli();
+ kernel_process = kmalloc(sizeof(struct process)); //This process must be hidden to users
+ kernel_process->pid = kernel_process->uid = kernel_process->threads = 0;
+ kernel_process->privilege = PL_KERNEL;
+ kernel_process->parent = kernel_process;
+ kernel_process->pagedir = kernel_pagedir;
+ kernel_process->next = 0;
+ current_thread = 0;
+ idle_thread = thread_new(kernel_process, task_idle, 0);
+ threads = 0; //Do not include idle thread in threads
+ sti();
+ monitor_write("Tasking set up\n");
+}
+
+static struct thread *thread_next() {
+ if (current_thread == 0 || current_thread == idle_thread) current_thread = threads;
+ struct thread *ret = current_thread;
+ while (1) {
+ ret = ret->next;
+ if (ret == 0) ret = threads;
+ if (thread_runnable(ret)) {
+ return ret;
+ }
+ if (ret == current_thread) return idle_thread;
+ }
+}
+
+void tasking_switch() {
+ if (threads == 0) PANIC("No more threads to run !");
+ asm volatile("cli");
+
+ uint32_t esp, ebp, eip;
+
+ asm volatile("mov %%esp, %0" : "=r"(esp));
+ asm volatile("mov %%ebp, %0" : "=r"(ebp));
+ eip = read_eip();
+
+ if (eip == 0x12345) {
+ return;
+ }
+
+ if (current_thread != 0) {
+ current_thread->esp = esp;
+ current_thread->ebp = ebp;
+ current_thread->eip = eip;
+ }
+
+ current_thread = thread_next();
+
+ asm volatile(" \
+ mov %0, %%ebp; \
+ mov %1, %%esp; \
+ mov %2, %%ecx; \
+ mov $0x12345, %%eax; \
+ jmp *%%ecx;"
+ : : "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;
+ }
+}
+
+uint32_t tasking_handleException(struct registers *regs) {
+ if (current_thread == 0) return 0; //No tasking yet
+ monitor_write("\n(task.c:99) Unhandled exception : ");
+ char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint",
+ "Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault",
+ "Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault",
+ "Page Fault","Unknown Interrupt","Coprocessor Fault","Alignment Check","Machine Check"};
+ monitor_write(exception_messages[regs->int_no]);
+ monitor_write(" at "); monitor_writeHex(regs->eip);
+ monitor_write(" >>> Thread exiting.\n");
+ thread_exit_stackJmp(EX_TH_EXCEPTION);
+ PANIC("This should never have happened. Please report this.");
+}
+
+void thread_sleep(uint32_t msecs) {
+ if (current_thread == 0) return;
+ current_thread->state = TS_SLEEPING;
+ current_thread->timeWait = timer_time() + msecs;
+ asm volatile("int $64" : : "a"(1));
+}
+
+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
+ * if reason == EX_TH_EXCEPTION, it is just one thread exiting because of an exception
+ * if reason is none of the two cases above, it is the whole process exiting (with error code = reason)
+ */
+ struct thread *th = current_thread;
+ struct process *pr = th->process;
+ if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->threads > 1) {
+ thread_delete(th);
+ } else {
+ process_delete(pr);
+ }
+ sti();
+ tasking_switch();
+}
+
+void thread_exit_stackJmp(uint32_t reason) {
+ uint32_t *stack;
+ cli();
+ stack = tasking_tmpStack + 0x4000;
+ stack--; *stack = reason;
+ stack--; *stack = 0;
+ asm volatile(" \
+ mov %0, %%esp; \
+ mov %1, %%ebp; \
+ mov %2, %%ecx; \
+ mov %3, %%cr3; \
+ jmp *%%ecx;" : :
+ "r"(stack), "r"(stack), "r"(thread_exit2), "r"(kernel_pagedir->physicalAddr));
+}
+
+void thread_exit() {
+ thread_exit_stackJmp(EX_TH_NORMAL);
+}
+
+void process_exit(uint32_t retval) {
+ if (retval == EX_TH_NORMAL || retval == EX_TH_EXCEPTION) retval = EX_PR_EXCEPTION;
+ thread_exit_stackJmp(retval);
+}
+
+static uint32_t thread_runnable(struct thread *t) {
+ if (t->state == TS_RUNNING) return 1;
+ if (t->state == TS_SLEEPING && timer_time() >= t->timeWait) return 1;
+ return 0;
+}
+
+static void thread_run(struct thread *thread, thread_entry entry_point, void *data) {
+ pagedir_switch(thread->process->pagedir); //TODO : take into account privilege level
+ asm volatile("sti");
+ entry_point(data);
+ thread_exit(0);
+}
+
+struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data) {
+ struct thread *t = kmalloc(sizeof(struct thread));
+ t->process = proc;
+ proc->threads++;
+ t->kernelStack_addr = kmalloc(KSTACKSIZE);
+ t->kernelStack_size = KSTACKSIZE;
+
+ uint32_t *stack = (uint32_t*)((size_t)t->kernelStack_addr + t->kernelStack_size);
+
+ //Pass parameters
+ stack--; *stack = (uint32_t)data;
+ stack--; *stack = (uint32_t)entry_point;
+ stack--; *stack = (uint32_t)t;
+ stack--; *stack = 0;
+ t->esp = (uint32_t)stack;
+ t->ebp = t->esp + 8;
+ t->eip = (uint32_t)thread_run;
+
+ t->state = TS_RUNNING;
+
+ if (threads == 0) {
+ threads = t;
+ } else {
+ struct thread *i = threads;
+ while (i->next != 0) i = i->next;
+ i->next = t;
+ }
+ return t;
+}
+
+struct process *process_new(struct process* parent, uint32_t uid, uint32_t privilege) {
+ struct process* p = kmalloc(sizeof(struct process));
+ p->pid = (nextpid++);
+ p->uid = uid;
+ p->threads = 0;
+ p->privilege = privilege;
+ p->parent = parent;
+ p->pagedir = pagedir_new();
+ p->next = processes;
+ processes = p;
+ return p;
+}
+
+static void thread_delete(struct thread *th) {
+ kfree(th->kernelStack_addr);
+ th->process->threads--;
+ if (threads == th) {
+ threads = th->next;
+ } else {
+ struct thread *it = threads;
+ while (it->next != th && it->next != 0) it = it->next;
+ if (it->next == th) it->next = th->next;
+ }
+ kfree(th);
+}
+
+static void process_delete(struct process *pr) {
+ struct thread *it;
+ while (threads != 0 && threads->process == pr) thread_delete(threads);
+ it = threads;
+ while (it != 0) {
+ while (it->next->process == pr) thread_delete(it->next);
+ it = it->next;
+ }
+ pagedir_delete(pr->pagedir);
+ if (processes == pr) {
+ processes = pr->next;
+ } else {
+ struct process *it = processes;
+ while (it != 0 && it->next != pr) it = it->next;
+ if (it != 0 && it->next == pr) it->next = pr->next;
+ }
+ kfree(pr);
+}
diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h
new file mode 100644
index 0000000..c9f1794
--- /dev/null
+++ b/src/kernel/task/task.h
@@ -0,0 +1,55 @@
+#ifndef DEF_TASK_H
+#define DEF_TASK_H
+
+#include <types.h>
+#include <mem/paging.h>
+#include "idt.h"
+
+#define TS_RUNNING 0
+#define TS_SLEEPING 1 //Sleeping for a defined amount of time
+#define TS_WAIKWAIT 2 //Waiting to be waked up by something precise (thread currently blocked)
+
+#define PL_USER 3
+#define PL_SERVICE 2
+#define PL_DRIVER 1
+#define PL_KERNEL 0
+
+#define EX_TH_NORMAL 0x10000 //ERROR code : just one thread exits, because it has to
+#define EX_TH_EXCEPTION 0x10001 //ERROR code : just one thread exits, because of an unhandled exception
+#define EX_PR_EXCEPTION 0x10002 //ERROR code : all process finishes, because of an unhandled exception
+
+typedef void (*thread_entry)(void*);
+
+struct process {
+ uint32_t pid, uid, privilege, threads;
+ struct process *parent;
+ struct page_directory *pagedir;
+
+ struct process *next; //Forms a linked list
+};
+
+struct thread {
+ struct process *process;
+ uint32_t esp, ebp, eip;
+ uint8_t state;
+ uint32_t timeWait;
+ void* kernelStack_addr;
+ uint32_t kernelStack_size;
+
+ struct thread *next; //Forms a linked list
+};
+
+extern struct thread *current_thread;
+
+void tasking_init();
+void tasking_switch();
+void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablePhysical);
+uint32_t tasking_handleException(struct registers *regs);
+
+void thread_sleep(uint32_t msecs);
+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);
+
+#endif
diff --git a/src/kernel/task/task_.asm b/src/kernel/task/task_.asm
new file mode 100644
index 0000000..ae45c68
--- /dev/null
+++ b/src/kernel/task/task_.asm
@@ -0,0 +1,10 @@
+[GLOBAL read_eip]
+read_eip:
+ pop eax
+ jmp eax
+
+[GLOBAL task_idle]
+task_idle:
+ sti
+ hlt
+ jmp task_idle
diff --git a/src/kernel/task/timer.c b/src/kernel/task/timer.c
new file mode 100644
index 0000000..8c1a2b8
--- /dev/null
+++ b/src/kernel/task/timer.c
@@ -0,0 +1,36 @@
+#include "timer.h"
+#include "idt.h"
+#include <core/sys.h>
+#include <core/monitor.h>
+
+static uint32_t tick = 0, frequency = 0, uptime = 0;
+
+void timer_callback(struct registers *regs) {
+ tick++;
+ if (tick == frequency) {
+ uptime++;
+ tick = 0;
+ }
+}
+
+uint32_t timer_uptime() { return uptime; }
+
+uint32_t timer_time() {
+ return (uptime * 1000) + (tick * 1000 / frequency);
+}
+
+void timer_init(uint32_t freq) {
+ frequency = freq;
+
+ idt_handleIrq(0, timer_callback);
+
+ uint32_t divisor = 1193180 / freq;
+
+ outb(0x43, 0x36); //Command byte
+
+ uint8_t l = (divisor & 0xFF), h = (divisor >> 8);
+ outb(0x40, l);
+ outb(0x40, h);
+
+ monitor_write("Timer started\n");
+}
diff --git a/src/kernel/task/timer.h b/src/kernel/task/timer.h
new file mode 100644
index 0000000..4909245
--- /dev/null
+++ b/src/kernel/task/timer.h
@@ -0,0 +1,10 @@
+#ifndef DEF_TIMER_H
+#define DEF_TIMER_H
+
+#include <types.h>
+
+void timer_init(uint32_t frequency);
+uint32_t timer_time(); //Returns miliseconds (approximate) since computer started
+uint32_t timer_uptime(); //Same thing in seconds
+
+#endif