summaryrefslogtreecommitdiff
path: root/src/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel')
-rw-r--r--src/kernel/Makefile38
-rw-r--r--src/kernel/core/kmain.c63
-rw-r--r--src/kernel/core/loader_.asm57
-rw-r--r--src/kernel/core/monitor.c90
-rw-r--r--src/kernel/core/monitor.h12
-rw-r--r--src/kernel/core/multiboot.h64
-rw-r--r--src/kernel/core/sys.c41
-rw-r--r--src/kernel/core/sys.h17
-rw-r--r--src/kernel/lib/bitset.c35
-rw-r--r--src/kernel/lib/bitset.h19
-rw-r--r--src/kernel/lib/stdlib.c39
-rw-r--r--src/kernel/lib/stdlib.h12
-rw-r--r--src/kernel/lib/types.h15
-rw-r--r--src/kernel/link.ld32
-rw-r--r--src/kernel/linker/elf.c44
-rw-r--r--src/kernel/linker/elf.h63
-rw-r--r--src/kernel/mem/gdt.c36
-rw-r--r--src/kernel/mem/gdt.h23
-rw-r--r--src/kernel/mem/heap.c224
-rw-r--r--src/kernel/mem/heap.h27
-rw-r--r--src/kernel/mem/mem.c95
-rw-r--r--src/kernel/mem/mem.h17
-rw-r--r--src/kernel/mem/paging.c171
-rw-r--r--src/kernel/mem/paging.h46
-rw-r--r--src/kernel/mem/seg.c73
-rw-r--r--src/kernel/mem/seg.h40
-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
36 files changed, 2158 insertions, 0 deletions
diff --git a/src/kernel/Makefile b/src/kernel/Makefile
new file mode 100644
index 0000000..5af7f4b
--- /dev/null
+++ b/src/kernel/Makefile
@@ -0,0 +1,38 @@
+.PHONY: clean, mrproper
+
+CC = gcc
+CFLAGS = -nostdlib -nostartfiles -nodefaultlibs -fno-builtin -fno-stack-protector -Wall -Wextra -I . -I ./lib
+
+LD = ld
+LDFLAGS = -T link.ld
+
+ASM = nasm
+AFLAGS = -f elf
+
+OBJECTS = core/loader_.o core/kmain.o core/sys.o \
+ core/monitor.o task/timer.o \
+ task/idt.o task/idt_.o task/task.o task/task_.o task/syscall.o \
+ lib/stdlib.o lib/bitset.o \
+ mem/mem.o mem/paging.o mem/gdt.o mem/heap.o mem/seg.o \
+ linker/elf.o
+OUT = kernel.elf
+
+all: $(OBJECTS)
+ echo "* Linking $(OUT)..."
+ $(LD) $(LDFLAGS) $(OBJECTS) -o $(OUT) -Map kernel.map
+
+clean:
+ rm $(OBJECTS) || exit 0
+ rm *.o */*.o || exit 0
+ rm *.map || exit 0
+
+mrproper: clean
+ rm $(OUT) || exit 0
+
+%.o: %.asm
+ echo "* Compiling $<..."
+ $(ASM) $(AFLAGS) -o $@ $<
+
+%.o: %.c
+ echo "* Compiling $<..."
+ $(CC) -c $< -o $@ $(CFLAGS)
diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c
new file mode 100644
index 0000000..ef92dff
--- /dev/null
+++ b/src/kernel/core/kmain.c
@@ -0,0 +1,63 @@
+#include <types.h>
+#include "multiboot.h"
+#include "monitor.h"
+#include "sys.h"
+#include <task/idt.h>
+#include <task/timer.h>
+#include <task/task.h>
+#include <mem/gdt.h>
+#include <mem/paging.h>
+#include <mem/mem.h>
+#include <linker/elf.h>
+
+void kmain(struct multiboot_info_t* mbd, int32_t magic) {
+ size_t totalRam = 0;
+ uint32_t i;
+
+ mem_placementAddr = (size_t)&end;
+ mbd->cmdline += 0xE0000000; mbd->mods_addr += 0xE0000000;
+ struct module_t *mods = (struct module_t*)mbd->mods_addr;
+ for (i = 0; i < mbd->mods_count; i++) {
+ mods[i].mod_start += 0xE0000000;
+ mods[i].mod_end += 0xE0000000;
+ mods[i].string += 0xE0000000;
+ if (mods[i].mod_end > mem_placementAddr)
+ mem_placementAddr = (mods[i].mod_end & 0xFFFFF000) + 0x1000;
+ }
+
+ monitor_clear();
+
+ if (magic != MULTIBOOT_BOOTLOADER_MAGIC) {
+ PANIC("wrong multiboot magic number.");
+ }
+
+ monitor_write("Grapes kernel booting ...\n");
+
+ idt_init();
+
+ totalRam = ((mbd->mem_upper + mbd->mem_lower) * 1024);
+ paging_init(totalRam);
+ gdt_init();
+ paging_cleanup();
+ kheap_init();
+ timer_init(20);
+ tasking_init();
+
+ monitor_write("Loading modules...\n");
+ for (i = 0; i < mbd->mods_count; i++) {
+ monitor_write((char*)mods[i].string);
+ if (elf_check((uint8_t*)mods[i].mod_start)) {
+ monitor_write(" : Invalid ELF file\n");
+ } else {
+ if (elf_exec((uint8_t*)mods[i].mod_start) == 0) {
+ monitor_write(" : Error loading\n");
+ } else {
+ monitor_write(" : OK\n");
+ }
+ }
+ }
+
+ monitor_write("Passing control to loaded modules...\n");
+ sti();
+ tasking_switch();
+}
diff --git a/src/kernel/core/loader_.asm b/src/kernel/core/loader_.asm
new file mode 100644
index 0000000..d3b92cf
--- /dev/null
+++ b/src/kernel/core/loader_.asm
@@ -0,0 +1,57 @@
+[GLOBAL loader] ; making entry point visible to linker
+[EXTERN kmain] ; kmain is defined in kmain.c
+[EXTERN tasking_tmpStack] ; a temporary 4k stack used by tasking, and used when setting up kernel stuff
+
+; setting up the Multiboot header - see GRUB docs for details
+MODULEALIGN equ 1<<0 ; align loaded modules on page boundaries
+MEMINFO equ 1<<1 ; provide memory map
+FLAGS equ MODULEALIGN | MEMINFO ; this is the Multiboot 'flag' field
+MAGIC equ 0x1BADB002 ; 'magic number' lets bootloader find the header
+CHECKSUM equ -(MAGIC + FLAGS) ; checksum required
+
+section .text
+align 4
+MultiBootHeader:
+ dd MAGIC
+ dd FLAGS
+ dd CHECKSUM
+
+section .setup
+loader: ;here, we load our false GDT, used for having the kernel in higher half
+ lgdt [trickgdt]
+ mov cx, 0x10;
+ mov ds, cx;
+ mov es, cx;
+ mov fs, cx;
+ mov gs, cx;
+ mov ss, cx;
+
+ jmp 0x08:higherhalf
+
+section .text
+higherhalf: ; now we're running in higher half
+
+ mov esp, tasking_tmpStack+0x4000 ; set up the stack
+ push eax ; pass Multiboot magic number
+ add ebx, 0xE0000000 ; update the MB info structure so that it is in the new seg
+ push ebx ; pass Multiboot info structure
+
+ call kmain ; call kernel proper
+
+ cli ; disable interupts
+hang:
+ hlt ; halt machine should kernel return
+ jmp hang
+
+[section .setup] ; this is included in the .setup section, so that it thinks it is at 0x00100000
+
+trickgdt: ; our false GDT
+ dw gdt_end - gdt - 1 ; gdt limit
+ dd gdt ; gdt base
+
+gdt:
+ dd 0, 0 ; null GDT entry
+ db 0xFF, 0xFF, 0, 0, 0, 10011010b, 11001111b, 0x20 ; kernel code segment
+ db 0xFF, 0xFF, 0, 0, 0, 10010010b, 11001111b, 0x20 ; kernel data segment
+
+gdt_end:
diff --git a/src/kernel/core/monitor.c b/src/kernel/core/monitor.c
new file mode 100644
index 0000000..8c4744a
--- /dev/null
+++ b/src/kernel/core/monitor.c
@@ -0,0 +1,90 @@
+#include "monitor.h"
+#include "sys.h"
+
+static int cursor_x = 0, cursor_y = 0;
+static uint16_t *video_memory = (uint16_t*)0xE00B8000;
+
+static void move_cursor() {
+ uint16_t cursor_location = cursor_y * 80 + cursor_x;
+ outb(0x3D4, 14); //Sending high cursor byte
+ outb(0x3D5, cursor_location >> 8);
+ outb(0x3D4, 15); //Sending high cursor byte
+ outb(0x3D5, cursor_location);
+}
+
+static void scroll() {
+ uint8_t attribute_byte = (0 /* black */ << 4) | (7/* white */ & 0x0F);
+ uint16_t blank = (attribute_byte << 8) | 0x20;
+
+ if (cursor_y >= 25) {
+ int i;
+ for (i = 0; i < 80*24; i++) {
+ video_memory[i] = video_memory[i+80];
+ }
+ for (i = 80*24; i < 80*25; i++) {
+ video_memory[i] = blank;
+ }
+ cursor_y = 24;
+ }
+}
+
+void monitor_put(char c) {
+ uint8_t fg = 7; //White
+ uint8_t bg = 0; //Black
+
+ uint16_t attribute = (fg & 0x0F) | (bg << 4);
+ attribute = attribute << 8;
+
+ if (c == 0x08 && cursor_x) { //Backspace
+ cursor_x--;
+ } else if (c == 0x09) { //Tab
+ cursor_x = (cursor_x + 8) & ~(8 - 1);
+ } else if (c == '\r') { //Carriage return
+ cursor_x = 0;
+ } else if (c == '\n') { //New line
+ cursor_x = 0;
+ cursor_y++;
+ } else if (c >= ' ') { //Any printable character
+ video_memory[cursor_y * 80 + cursor_x] = c | attribute;
+ cursor_x++;
+ }
+ if (cursor_x >= 80) {
+ cursor_x = 0;
+ cursor_y++;
+ }
+
+ scroll();
+ move_cursor();
+}
+
+void monitor_clear() {
+ uint8_t attribute_byte = (0 /* black */ << 4) | (15 /* white */ & 0x0F);
+ uint16_t blank = (attribute_byte << 8) | 0x20;
+
+ int i;
+
+ for (i = 0; i < 80*25; i++) {
+ video_memory[i] = blank;
+ }
+
+ cursor_x = 0; cursor_y = 0;
+ move_cursor();
+}
+
+void monitor_write(char *s) {
+ while (*s) {
+ monitor_put(*(s++));
+ }
+}
+
+void monitor_writeHex(uint32_t v) {
+ int i;
+
+ monitor_put('0'); monitor_put('x');
+ char hexdigits[] = "0123456789abcdef";
+
+ for (i = 0; i < 8; i++) {
+ monitor_put(hexdigits[v >> 28]);
+ v = v << 4;
+ }
+}
diff --git a/src/kernel/core/monitor.h b/src/kernel/core/monitor.h
new file mode 100644
index 0000000..3abe072
--- /dev/null
+++ b/src/kernel/core/monitor.h
@@ -0,0 +1,12 @@
+#ifndef DEF_MONITOR_H
+#define DEF_MONITOR_H
+
+#include "types.h"
+
+void monitor_put(char c);
+void monitor_clear();
+void monitor_write(char *s);
+void monitor_writeHex(uint32_t v);
+
+#endif
+
diff --git a/src/kernel/core/multiboot.h b/src/kernel/core/multiboot.h
new file mode 100644
index 0000000..908274c
--- /dev/null
+++ b/src/kernel/core/multiboot.h
@@ -0,0 +1,64 @@
+#ifndef HDR_MULTIBOOT
+#define HDR_MULTIBOOT
+#define MULTIBOOT_HEADER_MAGIC 0x1BADB002
+#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002
+
+struct multiboot_header_t{
+ unsigned long magic;
+ unsigned long flags;
+ unsigned long checksum;
+ unsigned long header_addr;
+ unsigned long load_addr;
+ unsigned long load_end_addr;
+ unsigned long bss_end_addr;
+ unsigned long entry_addr;
+};
+
+struct aout_symbol_table_t {
+ unsigned long tabsize;
+ unsigned long strsize;
+ unsigned long addr;
+ unsigned long reserved;
+};
+
+struct elf_section_header_table_t {
+ unsigned long num;
+ unsigned long size;
+ unsigned long addr;
+ unsigned long shndx;
+};
+
+struct multiboot_info_t {
+ unsigned long flags;
+ unsigned long mem_lower;
+ unsigned long mem_upper;
+ unsigned long boot_device;
+ unsigned long cmdline;
+ unsigned long mods_count;
+ unsigned long mods_addr;
+ union {
+ struct aout_symbol_table_t aout_sym;
+ struct elf_section_header_table_t elf_sec;
+ } u;
+ unsigned long mmap_length;
+ unsigned long mmap_addr;
+};
+
+struct module_t {
+ unsigned long mod_start;
+ unsigned long mod_end;
+ unsigned long string;
+ unsigned long reserved;
+};
+
+struct memory_map_t {
+ unsigned long size;
+ unsigned long base_addr_low;
+ unsigned long base_addr_high;
+ unsigned long length_low;
+ unsigned long length_high;
+ unsigned long type;
+};
+
+#endif
+
diff --git a/src/kernel/core/sys.c b/src/kernel/core/sys.c
new file mode 100644
index 0000000..d31c20e
--- /dev/null
+++ b/src/kernel/core/sys.c
@@ -0,0 +1,41 @@
+#include "sys.h"
+#include "monitor.h"
+
+void outb(uint16_t port, uint8_t value) {
+ asm volatile("outb %1, %0" : : "dN"(port), "a"(value));
+}
+
+void outw(uint16_t port, uint16_t value) {
+ asm volatile("outw %1, %0" : : "dN"(port), "a"(value));
+}
+
+uint8_t inb(uint16_t port) {
+ uint8_t ret;
+ asm volatile("inb %1, %0" : "=a"(ret) : "dN"(port));
+ return ret;
+}
+
+uint16_t inw(uint16_t port) {
+ uint16_t ret;
+ asm volatile("inw %1, %0" : "=a"(ret) : "dN"(port));
+ return ret;
+}
+
+void panic(char* message, char* file, int line) {
+ monitor_write("\n>> PANIC: >>");
+ monitor_write(message); monitor_write("<< in file "); monitor_write(file);
+ monitor_write("\nSystem halted T_T");
+ asm volatile("cli; hlt");
+}
+
+static uint32_t if_locks = 1;
+
+void cli() {
+ asm volatile("cli");
+ if_locks++;
+}
+
+void sti() {
+ if (if_locks > 0) if_locks--;
+ if (if_locks == 0) asm volatile("sti");
+}
diff --git a/src/kernel/core/sys.h b/src/kernel/core/sys.h
new file mode 100644
index 0000000..76e3560
--- /dev/null
+++ b/src/kernel/core/sys.h
@@ -0,0 +1,17 @@
+#ifndef DEF_SYS_H
+#define DEF_SYS_H
+
+#include "types.h"
+
+void outb(uint16_t port, uint8_t value);
+void outw(uint16_t port, uint16_t value);
+uint8_t inb(uint16_t port);
+uint16_t inw(uint16_t port);
+
+#define PANIC(s) panic(s, __FILE__, __LINE__);
+void panic(char* message, char* file, int line);
+
+void sti(); //GLOBAL SYSTEM MUTEX
+void cli();
+
+#endif
diff --git a/src/kernel/lib/bitset.c b/src/kernel/lib/bitset.c
new file mode 100644
index 0000000..a6d334b
--- /dev/null
+++ b/src/kernel/lib/bitset.c
@@ -0,0 +1,35 @@
+#include "bitset.h"
+
+void bitset_set(struct bitset* t, uint32_t num) {
+ uint32_t idx = INDEX_FROM_BIT(num);
+ uint32_t off = OFFSET_FROM_BIT(num);
+ t->bits[idx] |= (0x1 << off);
+}
+
+void bitset_clear(struct bitset* t, uint32_t num) {
+ uint32_t idx = INDEX_FROM_BIT(num);
+ uint32_t off = OFFSET_FROM_BIT(num);
+ t->bits[idx] &= ~(0x1 << off);
+}
+
+uint32_t bitset_test(struct bitset* t, uint32_t num) {
+ uint32_t idx = INDEX_FROM_BIT(num);
+ uint32_t off = OFFSET_FROM_BIT(num);
+ return (t->bits[idx] & (0x1 << off));
+}
+
+uint32_t bitset_firstFree(struct bitset* t) {
+ uint32_t i, j;
+ for (i = 0; i < INDEX_FROM_BIT(t->size); i++) {
+ if (t->bits[i] != 0xFFFFFFFF) {
+ for (j = 0; j < 32; j++) {
+ uint32_t toTest = 0x1 << j;
+ if (!(t->bits[i] & toTest)) {
+ return i*4*8+j;
+ }
+ }
+ }
+ }
+ return (uint32_t) - 1;
+}
+
diff --git a/src/kernel/lib/bitset.h b/src/kernel/lib/bitset.h
new file mode 100644
index 0000000..fe9e8c2
--- /dev/null
+++ b/src/kernel/lib/bitset.h
@@ -0,0 +1,19 @@
+#ifndef DEF_BITSET_H
+#define DEF_BITSET_H
+
+#include <types.h>
+
+#define INDEX_FROM_BIT(a) (a/(8*4))
+#define OFFSET_FROM_BIT(a) (a%(8*4))
+
+struct bitset {
+ uint32_t *bits;
+ uint32_t size;
+};
+
+void bitset_set(struct bitset* t, uint32_t num);
+void bitset_clear(struct bitset* t, uint32_t num);
+uint32_t bitset_test(struct bitset* t, uint32_t num);
+uint32_t bitset_firstFree(struct bitset* t);
+
+#endif
diff --git a/src/kernel/lib/stdlib.c b/src/kernel/lib/stdlib.c
new file mode 100644
index 0000000..c5245e7
--- /dev/null
+++ b/src/kernel/lib/stdlib.c
@@ -0,0 +1,39 @@
+#include "stdlib.h"
+
+void *memcpy(void *vd, const void *vs, int count) {
+ uint8_t *dest = (uint8_t*)vd, *src = (uint8_t*)vs;
+ uint32_t f = count % 4, n = count / 4, i;
+ const uint32_t* s = (uint32_t*)src;
+ uint32_t* d = (uint32_t*)dest;
+ for (i = 0; i < n; i++) {
+ d[i] = s[i];
+ }
+ if (f != 0) {
+ for (i = count - f; i < count; i++) {
+ dest[i] = src[i];
+ }
+ }
+ return vd;
+}
+
+uint8_t *memset(uint8_t *dest, uint8_t val, int count) {
+ int i;
+ for (i = 0; i < count; i++) {
+ dest[i] = val;
+ }
+ return dest;
+}
+
+uint16_t *memsetw(uint16_t *dest, uint16_t val, int count) {
+ int i;
+ for (i = 0; i < count; i++) {
+ dest[i] = val;
+ }
+ return dest;
+}
+
+int strlen(const char *str) {
+ int i = 0;
+ while (str[i++]);
+ return i;
+}
diff --git a/src/kernel/lib/stdlib.h b/src/kernel/lib/stdlib.h
new file mode 100644
index 0000000..704c410
--- /dev/null
+++ b/src/kernel/lib/stdlib.h
@@ -0,0 +1,12 @@
+#ifndef DEF_STDLIB_H
+#define DEF_STDLIB_H
+
+#include <types.h>
+
+void *memcpy(void *dest, const void *src, int count);
+uint8_t *memset(uint8_t *dest, uint8_t val, int count);
+uint16_t *memsetw(uint16_t *dest, uint16_t val, int count);
+int strlen(const char *str);
+
+#endif
+
diff --git a/src/kernel/lib/types.h b/src/kernel/lib/types.h
new file mode 100644
index 0000000..b7b19ab
--- /dev/null
+++ b/src/kernel/lib/types.h
@@ -0,0 +1,15 @@
+#ifndef DEF_TYPES_H
+#define DEF_TYPES_H
+
+typedef unsigned long long uint64_t;
+typedef unsigned int uint32_t;
+typedef unsigned short uint16_t;
+typedef unsigned char uint8_t;
+typedef long long int64_t;
+typedef int int32_t;
+typedef short int16_t;
+typedef char int8_t;
+
+typedef unsigned int size_t;
+
+#endif
diff --git a/src/kernel/link.ld b/src/kernel/link.ld
new file mode 100644
index 0000000..1ce17cf
--- /dev/null
+++ b/src/kernel/link.ld
@@ -0,0 +1,32 @@
+ENTRY (loader)
+
+SECTIONS{
+ . = 0x00100000;
+
+ .setup : {
+ *(.setup)
+ }
+
+ . += 0xE0000000;
+
+ .text : AT(ADDR(.text) - 0xE0000000) {
+ *(.text)
+ }
+
+ .rodata ALIGN (0x1000) : AT(ADDR(.rodata) - 0xE0000000) {
+ *(.rodata)
+ }
+
+ .data ALIGN (0x1000) : AT(ADDR(.data) - 0xE0000000) {
+ *(.data)
+ }
+
+ .bss : AT(ADDR(.bss) - 0xE0000000) {
+ sbss = .;
+ *(COMMON)
+ *(.bss)
+ ebss = .;
+ }
+
+ end = .; _end = .; __end = .;
+}
diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c
new file mode 100644
index 0000000..dc7481b
--- /dev/null
+++ b/src/kernel/linker/elf.c
@@ -0,0 +1,44 @@
+#include "elf.h"
+#include <mem/paging.h>
+#include <mem/seg.h>
+#include <stdlib.h>
+#include <core/sys.h>
+
+int elf_check(uint8_t *data) {
+ struct elf_ehdr *h = (struct elf_ehdr*)data;
+ if (h->e_ident[0] == 0x7F && h->e_ident[1] == 'E' && h->e_ident[2] == 'L' && h->e_ident[3] == 'F') return 0;
+ return 1;
+}
+
+thread_entry elf_load(uint8_t *data, struct process* process) {
+ struct elf_ehdr *ehdr = (struct elf_ehdr*)data;
+ struct elf_phdr *phdr;
+ int i;
+ if (elf_check(data)) return 0;
+
+ pagedir_switch(process->pagedir);
+
+ phdr = (struct elf_phdr*)((uint8_t*)(data + ehdr->e_phoff));
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_type == PT_LOAD) {
+ seg_map(simpleseg_make(phdr[i].p_vaddr, phdr[i].p_memsz, (phdr[i].p_flags & PF_W) != 0), process->pagedir);
+ memcpy((uint8_t*)phdr[i].p_vaddr, data + phdr[i].p_offset, phdr[i].p_filesz);
+ if (phdr[i].p_memsz > phdr[i].p_filesz) {
+ memset((uint8_t*)phdr[i].p_vaddr + phdr[i].p_memsz, 0, phdr[i].p_memsz - phdr[i].p_filesz);
+ }
+ }
+ }
+ return (thread_entry)ehdr->e_entry;
+}
+
+struct process* elf_exec(uint8_t *data) {
+ if (elf_check(data)) return 0;
+
+ struct process* p = process_new(0, 0, PL_DRIVER);
+
+ thread_entry e = elf_load(data, p);
+
+ thread_new(p, e, 0);
+
+ return p;
+}
diff --git a/src/kernel/linker/elf.h b/src/kernel/linker/elf.h
new file mode 100644
index 0000000..f84bb62
--- /dev/null
+++ b/src/kernel/linker/elf.h
@@ -0,0 +1,63 @@
+#ifndef DEF_ELF_H
+#define DEF_ELF_H
+
+#include <types.h>
+#include <task/task.h>
+
+/* elf_phdr_t :: p_type : program header entries types */
+#define PT_NULL 0
+#define PT_LOAD 1
+#define PT_DYNAMIC 2
+#define PT_INTERP 3
+#define PT_NOTE 4
+#define PT_SHLIB 5
+#define PT_PHDR 6
+#define PT_LOPROC 0x70000000
+#define PT_HIPROC 0x7fffffff
+
+/* elf_phdr_t :: p_flags : program header entries flags */
+#define PF_X (1 << 0)
+#define PF_W (1 << 1)
+#define PF_R (1 << 2)
+
+struct elf_ehdr {
+ uint8_t e_ident[16]; /* ELF identification */
+ uint16_t e_type; /* 2 (exec file) */
+ uint16_t e_machine; /* 3 (intel architecture) */
+ uint32_t e_version; /* 1 */
+ uint32_t e_entry; /* starting point */
+ uint32_t e_phoff; /* program header table offset */
+ uint32_t e_shoff; /* section header table offset */
+ uint32_t e_flags; /* various flags */
+ uint16_t e_ehsize; /* ELF header (this) size */
+
+ uint16_t e_phentsize; /* program header table entry size */
+ uint16_t e_phnum; /* number of entries */
+
+ uint16_t e_shentsize; /* section header table entry size */
+ uint16_t e_shnum; /* number of entries */
+
+ uint16_t e_shstrndx; /* index of the section name string table */
+};
+
+struct elf_phdr {
+ uint32_t p_type; /* type of segment */
+ uint32_t p_offset;
+ uint32_t p_vaddr;
+ uint32_t p_paddr;
+ uint32_t p_filesz;
+ uint32_t p_memsz;
+ uint32_t p_flags;
+ uint32_t p_align;
+};
+
+struct phdr {
+ struct elf_phdr h;
+ uint8_t* data;
+};
+
+int elf_check(uint8_t *data); //0 if ok, 1 if not a valid ELF
+thread_entry elf_load(uint8_t *data, struct process* process); //Load an ELF to a process, return entry point
+struct process* elf_exec(uint8_t *data); //Creates a new process and a thread for running ELF file
+
+#endif
diff --git a/src/kernel/mem/gdt.c b/src/kernel/mem/gdt.c
new file mode 100644
index 0000000..5aaad41
--- /dev/null
+++ b/src/kernel/mem/gdt.c
@@ -0,0 +1,36 @@
+#include "gdt.h"
+#include <stdlib.h>
+#include <core/monitor.h>
+
+extern void gdt_flush(uint32_t); //ASM (idt_.asm)
+
+#define GDT_ENTRIES 5
+
+static struct gdt_entry gdt_entries[GDT_ENTRIES];
+static struct gdt_ptr gdt_ptr;
+
+static void gdt_setGate(int num, uint32_t base, uint32_t limit, uint8_t access, uint8_t gran) {
+ gdt_entries[num].base_low = (base & 0xFFFF);
+ gdt_entries[num].base_middle = (base >> 16) & 0xFF;
+ gdt_entries[num].base_high = (base >> 24) & 0xFF;
+
+ gdt_entries[num].limit_low = (limit & 0xFFFF);
+ gdt_entries[num].granularity = (limit >> 16) & 0x0F;
+ gdt_entries[num].granularity |= gran & 0xF0;
+ gdt_entries[num].access = access;
+}
+
+void gdt_init() {
+ gdt_ptr.limit = (sizeof(struct gdt_entry) * GDT_ENTRIES) - 1;
+ gdt_ptr.base = (uint32_t)&gdt_entries;
+
+ gdt_setGate(0, 0, 0, 0, 0); //Null segment
+ gdt_setGate(1, 0, 0xFFFFFFFF, 0x9A, 0xCF); //Kernel code segment
+ gdt_setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment
+ gdt_setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment
+ gdt_setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment
+
+ gdt_flush((uint32_t)&gdt_ptr);
+
+ monitor_write("GDT ok\n");
+}
diff --git a/src/kernel/mem/gdt.h b/src/kernel/mem/gdt.h
new file mode 100644
index 0000000..aac16bb
--- /dev/null
+++ b/src/kernel/mem/gdt.h
@@ -0,0 +1,23 @@
+#ifndef DEF_GDT_H
+#define DEF_GDT_H
+
+#include <types.h>
+
+struct gdt_entry {
+ uint16_t limit_low;
+ uint16_t base_low;
+ uint8_t base_middle;
+ uint8_t access;
+ uint8_t granularity;
+ uint8_t base_high;
+} __attribute__((packed));
+
+struct gdt_ptr {
+ uint16_t limit;
+ uint32_t base;
+} __attribute__((packed));
+
+void gdt_init();
+
+#endif
+
diff --git a/src/kernel/mem/heap.c b/src/kernel/mem/heap.c
new file mode 100644
index 0000000..b6d2cd4
--- /dev/null
+++ b/src/kernel/mem/heap.c
@@ -0,0 +1,224 @@
+#include "heap.h"
+#include "paging.h"
+
+#define HEAP_MAGIC 0xBAD0BEEF
+#define HEAP_MIN_SIZE 0x4000
+
+/* ******************* HEADER ****************** */
+
+static void heapIdx_insert(struct heap *heap, struct heap_header *e) {
+ if ((heap->idxused + sizeof(struct heap_header*) + (size_t)heap->idx) >= heap->start_addr) return;
+
+ uint32_t iterator = 0, pos;
+ while (iterator < heap->idxused && heap->idx[iterator]->size < e->size) {
+ if (heap->idx[iterator] == e) return;
+ iterator++;
+ }
+ if (iterator == heap->idxused) {
+ heap->idx[heap->idxused++] = e;
+ } else {
+ pos = iterator;
+ iterator = heap->idxused;
+ while (iterator > pos) {
+ heap->idx[iterator] = heap->idx[iterator - 1];
+ iterator--;
+ }
+ heap->idxused++;
+ heap->idx[pos] = e;
+ }
+}
+
+static void heapIdx_remove(struct heap *heap, struct heap_header *e) {
+ uint32_t iterator;
+ for (iterator = 0; iterator < heap->idxused; iterator++) {
+ if (heap->idx[iterator] == e) break;
+ }
+ if (iterator == heap->idxused) return;
+ heap->idxused--;
+ while (iterator < heap->idxused) {
+ heap->idx[iterator] = heap->idx[iterator + 1];
+ iterator++;
+ }
+}
+
+/* ******************** CONTENTS ********************* */
+
+void heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize) {
+ uint32_t i;
+
+ if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000;
+
+ heap->start_addr = start + idxsize;
+ heap->end_addr = start + idxsize + datasize;
+ heap->max_end = start + idxsize + maxdatasize;
+
+ for (i = start; i < heap->end_addr; i += 0x1000) {
+ page_map(pagedir_getPage(kernel_pagedir, i, 1), frame_alloc(), 0, 0);
+ }
+
+ heap->idx = (struct heap_header**)start;
+ heap->idxused = 0;
+
+ struct heap_header *hole = (struct heap_header*) heap->start_addr;
+ hole->size = (heap->end_addr - heap->start_addr);
+ hole->magic = HEAP_MAGIC;
+ hole->is_hole = 1;
+
+ struct heap_footer *hole_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
+ hole_footer->header = hole;
+ hole_footer->magic = HEAP_MAGIC;
+
+ heapIdx_insert(heap, hole);
+}
+
+static uint32_t heap_expand(struct heap *heap, size_t quantity) {
+ uint32_t i;
+
+ if (quantity & 0x0FFF) {
+ quantity = (quantity & 0xFFFFF000) + 0x1000;
+ }
+
+ if (heap->end_addr + quantity > heap->max_end) return 0;
+
+ size_t newEnd = heap->end_addr + quantity;
+
+ for (i = heap->end_addr; i < newEnd; i += 0x1000) {
+ page_map(pagedir_getPage(kernel_pagedir, i, 1), frame_alloc(), 0, 0);
+ }
+
+ struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
+ struct heap_header *last_header = last_footer->header;
+ if (last_header->is_hole) {
+ heapIdx_remove(heap, last_header);
+ last_header->size += quantity;
+
+ last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer));
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+
+ heapIdx_insert(heap, last_header);
+ } else {
+ last_header = (struct heap_header*)heap->end_addr;
+ last_footer = (struct heap_footer*)(newEnd - sizeof(struct heap_footer));
+
+ last_header->is_hole = 1;
+ last_header->magic = HEAP_MAGIC;
+ last_header->size = quantity;
+
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+
+ heapIdx_insert(heap, last_header);
+ }
+
+ heap->end_addr = newEnd;
+
+ return 1;
+}
+
+static void heap_contract(struct heap *heap) {
+ struct heap_footer *last_footer = (struct heap_footer*)(heap->end_addr - sizeof(struct heap_footer));
+ struct heap_header *last_header = last_footer->header;
+
+ if (last_header->is_hole == 0) return;
+
+ size_t quantity = 0;
+ while ((heap->end_addr - heap->start_addr) - quantity > HEAP_MIN_SIZE &&
+ (last_header->size - quantity) > 0x1000)
+ quantity += 0x1000;
+ if (quantity == 0) return;
+
+ size_t newEnd = heap->end_addr - quantity;
+
+ heapIdx_remove(heap, last_header);
+ last_header->size -= quantity;
+ last_footer = (struct heap_footer*)((size_t)last_footer - quantity);
+ last_footer->magic = HEAP_MAGIC;
+ last_footer->header = last_header;
+ heapIdx_insert(heap, last_header);
+
+ for (heap->end_addr -= 0x1000; heap->end_addr >= newEnd; heap->end_addr -= 0x1000) {
+ page_unmapFree(pagedir_getPage(kernel_pagedir, heap->end_addr, 0));
+ }
+}
+
+void* heap_alloc(struct heap *heap, size_t sz) {
+ size_t newsize = sz + sizeof(struct heap_header) + sizeof(struct heap_footer);
+ uint32_t iterator = 0;
+
+ while (iterator < heap->idxused) {
+ if (heap->idx[iterator]->size >= newsize) break;
+ iterator++;
+ }
+
+ if (iterator == heap->idxused) { //No hole is big enough
+ if (heap_expand(heap, (sz & 0xFFFFF000) + 0x1000) == 0) return 0; //FAILED
+ return heap_alloc(heap, sz);
+ }
+
+ struct heap_header *loc = heap->idx[iterator];
+ struct heap_footer *footer = (struct heap_footer*)((size_t)loc + loc->size - sizeof(struct heap_footer));
+ loc->is_hole = 0;
+ heapIdx_remove(heap, loc);
+
+ //If we have enough space to create a USEFUL new hole next to the allocated block, do it.
+ //If we do not, we might return a block that is a few bytes bigger than neede.
+ if (loc->size > (newsize + sizeof(struct heap_header) + sizeof(struct heap_footer))) {
+ loc->size = newsize;
+
+ //Write footer for block we return
+ struct heap_footer *newfooter = (struct heap_footer*)((size_t)loc + newsize - sizeof(struct heap_footer));
+ newfooter->header = loc;
+ newfooter->magic = HEAP_MAGIC;
+
+ //Write header for new hole we create
+ struct heap_header *nextloc = (struct heap_header*)((size_t)loc + newsize);
+ nextloc->is_hole = 1;
+ nextloc->magic = HEAP_MAGIC;
+ nextloc->size = ((size_t)footer - (size_t)nextloc + sizeof(struct heap_footer));
+ footer->header = nextloc; //Update footer
+ footer->magic = HEAP_MAGIC;
+
+ heapIdx_insert(heap, nextloc);
+ }
+
+ return (void*)((size_t)loc + sizeof(struct heap_header));
+}
+
+void heap_free(struct heap *heap, void* ptr) {
+ if (ptr == 0) return;
+ if ((size_t)ptr < heap->start_addr || (size_t)ptr > heap->end_addr) return;
+
+ struct heap_header *header = (struct heap_header*)((size_t)ptr - sizeof(struct heap_header));
+ struct heap_footer *footer = (struct heap_footer*)((size_t)header + header->size - sizeof(struct heap_footer));
+ if (header->magic != HEAP_MAGIC || footer->magic != HEAP_MAGIC) return;
+
+ //Unify left
+ struct heap_footer *prev_footer = (struct heap_footer*)((size_t)header - sizeof(struct heap_footer));
+ if (prev_footer->magic == HEAP_MAGIC && prev_footer->header->is_hole) {
+ header = prev_footer->header;
+ heapIdx_remove(heap, header);
+
+ footer->header = header;
+ header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer));
+ }
+
+ //Unify right
+ struct heap_header *next_header = (struct heap_header*)((size_t)footer + sizeof(struct heap_footer));
+ if (next_header->magic == HEAP_MAGIC && next_header->is_hole) {
+ heapIdx_remove(heap, next_header);
+ footer = (struct heap_footer*)((size_t)footer + next_header->size);
+
+ footer->header = header;
+ header->size = ((size_t)footer - (size_t)header + sizeof(struct heap_footer));
+ }
+
+ header->is_hole = 1;
+
+ heapIdx_insert(heap, header);
+
+ if ((size_t)footer == (heap->end_addr - sizeof(struct heap_footer)) &&
+ header->size >= 0x2000 && (heap->end_addr - heap->start_addr > HEAP_MIN_SIZE)) {
+ heap_contract(heap);
+ }
+}
diff --git a/src/kernel/mem/heap.h b/src/kernel/mem/heap.h
new file mode 100644
index 0000000..39ba37e
--- /dev/null
+++ b/src/kernel/mem/heap.h
@@ -0,0 +1,27 @@
+#ifndef DEF_HEAP_H
+#define DEF_HEAP_H
+
+#include "types.h"
+
+struct heap_header {
+ uint32_t magic;
+ uint32_t is_hole;
+ size_t size;
+};
+
+struct heap_footer {
+ uint32_t magic;
+ struct heap_header *header;
+};
+
+struct heap {
+ struct heap_header **idx;
+ uint32_t idxused;
+ size_t start_addr, end_addr, max_end;
+};
+
+void heap_create(struct heap *heap, size_t start, size_t idxsize, size_t datasize, size_t maxdatasize);
+void* heap_alloc(struct heap *heap, size_t sz);
+void heap_free(struct heap *heap, void* ptr);
+
+#endif
diff --git a/src/kernel/mem/mem.c b/src/kernel/mem/mem.c
new file mode 100644
index 0000000..2f7e1c8
--- /dev/null
+++ b/src/kernel/mem/mem.c
@@ -0,0 +1,95 @@
+#include "mem.h"
+#include <core/sys.h>
+#include <core/monitor.h>
+#include "paging.h"
+#include "heap.h"
+
+#define FREEPAGESTOKEEP 5
+
+#define KHEAP_IDXSIZE 0x1000
+#define KHEAP_INITSIZE 0x8000
+#define KHEAP_MAXSIZE 0x08000000
+
+size_t mem_placementAddr;
+static uint32_t kheap_working = 0;
+
+
+// ******************************
+// PAGE ALLOCATION
+// ****************************
+static struct freepage {
+ size_t virt, phys;
+} freepages[FREEPAGESTOKEEP];
+uint32_t freepagecount = 0;
+
+static void get_free_pages() {
+ static uint32_t locked = 0;
+ uint32_t i;
+ if (locked) return;
+ locked = 1;
+ while (freepagecount < FREEPAGESTOKEEP) {
+ if (kheap_working) {
+ for (i = 0xFFFFF000; i >= 0xF0000000; i -= 0x1000) {
+ if (pagedir_getPage(kernel_pagedir, i, 1)->frame == 0) break;
+ }
+ freepages[freepagecount].virt = i;
+ freepages[freepagecount].phys = frame_alloc() * 0x1000;
+ page_map(pagedir_getPage(kernel_pagedir, i, 0), freepages[freepagecount].phys / 0x1000, 0, 0);
+ freepagecount++;
+ } else {
+ if (mem_placementAddr & 0xFFFFF000) {
+ mem_placementAddr &= 0xFFFFF000;
+ mem_placementAddr += 0x1000;
+ }
+ freepages[freepagecount].virt = (size_t)kmalloc(0x1000);
+ freepages[freepagecount].phys = freepages[freepagecount].virt - 0xE0000000;
+ freepagecount++;
+ }
+ }
+ locked = 0;
+}
+
+void* kmalloc_page(size_t *phys) {
+ cli();
+ get_free_pages();
+ freepagecount--;
+ *phys = freepages[freepagecount].phys;
+ size_t tmp = freepages[freepagecount].virt;
+ sti();
+ return (void*)tmp;
+}
+
+void kfree_page(void* ptr) {
+ size_t addr = (size_t)ptr;
+ if (kheap_working) { //With this we can know if paging works
+ page_unmapFree(pagedir_getPage(kernel_pagedir, addr, 0));
+ }
+}
+
+//***********************************
+// NORMAL MEMORY ALLOCATION
+// *************************
+
+static struct heap kheap;
+
+void kheap_init() {
+ heap_create(&kheap, (mem_placementAddr & 0xFFFFF000) + 0x1000, KHEAP_IDXSIZE, KHEAP_INITSIZE, KHEAP_MAXSIZE);
+ kheap_working = 1;
+ monitor_write("Kernel heap ok\n");
+}
+
+void* kmalloc(size_t size) {
+ if (kheap_working) {
+ return heap_alloc(&kheap, size);
+ } else {
+ size_t tmp = mem_placementAddr;
+ mem_placementAddr += size;
+ return (void*)tmp;
+ }
+}
+
+void kfree(void* ptr) {
+ if (kheap_working) {
+ heap_free(&kheap, ptr);
+ }
+}
diff --git a/src/kernel/mem/mem.h b/src/kernel/mem/mem.h
new file mode 100644
index 0000000..5417d5f
--- /dev/null
+++ b/src/kernel/mem/mem.h
@@ -0,0 +1,17 @@
+#ifndef DEF_MEM_H
+#define DEF_MEM_H
+
+#include <types.h>
+
+void* kmalloc_page(size_t *phys);
+void kfree_page(void* page);
+void* kmalloc(size_t size);
+void kfree(void* ptr);
+
+void kheap_init();
+
+extern size_t mem_placementAddr;
+extern void end; //Symbol defined by linker : end of kernel code
+
+#endif
+
diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c
new file mode 100644
index 0000000..27ce043
--- /dev/null
+++ b/src/kernel/mem/paging.c
@@ -0,0 +1,171 @@
+#include "paging.h"
+#include <bitset.h>
+#include <stdlib.h>
+#include <core/monitor.h>
+#include "mem.h"
+#include "seg.h"
+#include <core/sys.h>
+#include <task/task.h>
+
+static struct bitset frames;
+
+struct page_directory *kernel_pagedir, *current_pagedir;
+
+/* ACCESSOR FUNCTIONS FOR STATIC BITSET */
+uint32_t frame_alloc() {
+ uint32_t free = bitset_firstFree(&frames);
+ bitset_set(&frames, free);
+ return free;
+}
+
+void frame_free(uint32_t id) {
+ bitset_clear(&frames, id);
+}
+
+
+void paging_init(size_t totalRam) {
+ uint32_t i;
+
+ frames.size = totalRam / 0x1000;
+ frames.bits = kmalloc(INDEX_FROM_BIT(frames.size));
+
+ kernel_pagedir = kmalloc(sizeof(struct page_directory));
+ kernel_pagedir->mappedSegs = 0;
+ kernel_pagedir->tablesPhysical = kmalloc_page(&kernel_pagedir->physicalAddr);
+ for (i = 0; i < 1024; i++) {
+ kernel_pagedir->tables[i] = 0;
+ kernel_pagedir->tablesPhysical[i] = 0;
+ }
+
+ for (i = 0xE0000000; i < mem_placementAddr; i += 0x1000) {
+ page_map(pagedir_getPage(kernel_pagedir, i, 1), frame_alloc(), 0, 0);
+ }
+ for (i = 0; i < (mem_placementAddr - 0xE0000000) / 0x100000; i++) {
+ kernel_pagedir->tablesPhysical[i] = kernel_pagedir->tablesPhysical[i + 896];
+ kernel_pagedir->tables[i] = kernel_pagedir->tables[i + 896];
+ }
+
+ monitor_write("Page dir is at: ");
+ monitor_writeHex(kernel_pagedir->physicalAddr);
+ pagedir_switch(kernel_pagedir);
+ monitor_write("\nPaging started\n");
+}
+
+void paging_cleanup() {
+ uint32_t i;
+ for (i = 0; i < (mem_placementAddr - 0xE0000000) / 0x100000; i++) {
+ kernel_pagedir->tablesPhysical[i] = 0;
+ kernel_pagedir->tables[i] = 0;
+ }
+ monitor_write("Pages cleaned up\n");
+}
+
+void pagedir_switch(struct page_directory *pd) {
+ current_pagedir = pd;
+ asm volatile("mov %0, %%cr3" : : "r"(pd->physicalAddr));
+ uint32_t cr0;
+ asm volatile("mov %%cr0, %0" : "=r"(cr0));
+ cr0 |= 0x80000000;
+ asm volatile("mov %0, %%cr0" : : "r"(cr0));
+}
+
+struct page_directory *pagedir_new() {
+ uint32_t i;
+
+ struct page_directory *pd = kmalloc(sizeof(struct page_directory));
+ pd->tablesPhysical = kmalloc_page(&pd->physicalAddr);
+ pd->mappedSegs = 0;
+
+ for (i = 0; i < 1024; i++) {
+ pd->tables[i] = 0; pd->tablesPhysical[i] = 0;
+ }
+
+ for (i = 896; i < 1024; i++) {
+ pd->tables[i] = kernel_pagedir->tables[i];
+ pd->tablesPhysical[i] = kernel_pagedir->tablesPhysical[i];
+ }
+
+ return pd;
+}
+
+void pagedir_delete(struct page_directory *pd) {
+ uint32_t i;
+ //Unmap segments
+ while (pd->mappedSegs != 0) seg_unmap(pd->mappedSegs);
+ //Cleanup page tables
+ for (i = 0; i < 896; i++) {
+ kfree_page(pd->tables[i]);
+ }
+ kfree_page(pd->tablesPhysical);
+ kfree(pd);
+}
+
+uint32_t paging_fault(struct registers *regs) {
+ size_t addr;
+ struct segment_map *seg = 0;
+ asm volatile("mov %%cr2, %0" : "=r"(addr));
+
+ seg = current_pagedir->mappedSegs;
+ while (seg) {
+ if (seg->start <= addr && seg->start + seg->len > addr) break;
+ seg = seg->next;
+ }
+
+ if (seg != 0) {
+ if (seg->seg->handle_fault(seg, addr, (regs->err_code & 0x2) && (regs->eip < 0xE0000000)) != 0) seg = 0;
+ }
+
+ if (seg == 0) {
+ monitor_write("(paging.c:119) Unhandled Page Fault ");
+ if (regs->err_code & 0x1) monitor_write("present ");
+ if (regs->err_code & 0x2) monitor_write("write ");
+ if (regs->err_code & 0x4) monitor_write("user ");
+ if (regs->err_code & 0x8) monitor_write("rsvd ");
+ if (regs->err_code & 0x10) monitor_write("instructionfetch ");
+ monitor_write("@"); monitor_writeHex(addr); monitor_write("\n");
+ return 1;
+ }
+ return 0;
+}
+
+struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int make) {
+ address /= 0x1000;
+ uint32_t table_idx = address / 1024;
+
+ if (pd->tables[table_idx]) {
+ return &pd->tables[table_idx]->pages[address % 1024];
+ } else if (make) {
+ pd->tables[table_idx] = kmalloc_page(pd->tablesPhysical + table_idx);
+ if (table_idx >= 896)
+ tasking_updateKernelPagetable(table_idx, pd->tables[table_idx], pd->tablesPhysical[table_idx]);
+ memset((uint8_t*)pd->tables[table_idx], 0, 0x1000);
+ pd->tablesPhysical[table_idx] |= 0x07;
+ return &pd->tables[table_idx]->pages[address % 1024];
+ } else {
+ return 0;
+ }
+}
+
+void page_map(struct page *page, uint32_t frame, uint32_t user, uint32_t rw) {
+ if (page != 0 && page->frame == 0 && page->present == 0) {
+ page->present = 1;
+ page->rw = (rw ? 1 : 0);
+ page->user = (user ? 1 : 0);
+ page->frame = frame;
+ }
+}
+
+void page_unmap(struct page *page) {
+ if (page != 0) {
+ page->frame = 0;
+ page->present = 0;
+ }
+}
+
+void page_unmapFree(struct page *page) {
+ if (page != 0) {
+ if (page->frame != 0) frame_free(page->frame);
+ page->frame = 0;
+ page->present = 0;
+ }
+}
diff --git a/src/kernel/mem/paging.h b/src/kernel/mem/paging.h
new file mode 100644
index 0000000..cb76cd6
--- /dev/null
+++ b/src/kernel/mem/paging.h
@@ -0,0 +1,46 @@
+#ifndef DEF_PAGING_H
+#define DEF_PAGING_H
+
+#include <types.h>
+#include <task/idt.h>
+
+struct page {
+ uint32_t present : 1; //Page mapped to a frame ?
+ uint32_t rw : 1; //Page read/write ?
+ uint32_t user : 1; //Page user readable ?
+ uint32_t accessed : 1; //Was page accessed ?
+ uint32_t dirty : 1; //Was page modified ?
+ uint32_t unused : 7;
+ uint32_t frame : 20; //Frame address (physical address)
+};
+
+struct page_table {
+ struct page pages[1024];
+};
+
+struct segment_map;
+struct page_directory {
+ struct page_table *tables[1024]; //Virtual addresses of page tables
+ uint32_t *tablesPhysical; //Pointer to the virtual address of the page directory (contain phys addr of pt)
+ uint32_t physicalAddr; //Physical address of info above
+ struct segment_map *mappedSegs;
+};
+
+extern struct page_directory *kernel_pagedir;
+
+uint32_t frame_alloc();
+void frame_free(uint32_t id);
+
+void paging_init(size_t totalRam);
+void paging_cleanup();
+void pagedir_switch(struct page_directory *pd);
+struct page_directory *pagedir_new(); //Creates a brand new empty page directory for a process, with kernel pages
+void pagedir_delete(struct page_directory *pagedir);
+struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int make);
+void page_map(struct page *page, uint32_t frame, uint32_t user, uint32_t rw);
+void page_unmap(struct page *page);
+void page_unmapFree(struct page *page);
+
+uint32_t paging_fault(struct registers *regs); //returns a boolean : 1 if unhandled, 0 if ok
+
+#endif
diff --git a/src/kernel/mem/seg.c b/src/kernel/mem/seg.c
new file mode 100644
index 0000000..1452d61
--- /dev/null
+++ b/src/kernel/mem/seg.c
@@ -0,0 +1,73 @@
+#include "seg.h"
+#include "mem.h"
+
+struct segment_map *seg_map(struct segment* seg, struct page_directory *pagedir) {
+ struct segment_map *sm = seg->map(seg, pagedir);
+ if (sm == 0) return 0;
+ seg->mappings++;
+ sm->seg = seg;
+ sm->pagedir = pagedir;
+ sm->next = pagedir->mappedSegs;
+ pagedir->mappedSegs = sm;
+ return sm;
+}
+
+void seg_unmap(struct segment_map *map) {
+ map->seg->unmap(map);
+ if (map->pagedir->mappedSegs == map) {
+ map->pagedir->mappedSegs = map->pagedir->mappedSegs->next;
+ } else {
+ struct segment_map *m = map->pagedir->mappedSegs;
+ while (m->next != 0 && m->next != map) m = m->next;
+ if (m->next == map) m->next = map->next;
+ }
+ map->seg->mappings--;
+ if (map->seg->mappings == 0) {
+ map->seg->delete(map->seg);
+ kfree(map->seg->seg_data);
+ kfree(map->seg);
+ }
+ kfree (map);
+}
+
+// ************************************ SIMPLESEG stuff *************
+
+struct segment* simpleseg_make(size_t start, size_t len, int writable) {
+ struct simpleseg *ss = kmalloc(sizeof(struct simpleseg));
+ struct segment *se = kmalloc(sizeof(struct segment));
+ se->seg_data = ss;
+ se->mappings = 0;
+ se->map = simpleseg_map;
+ se->unmap = simpleseg_unmap;
+ se->delete = simpleseg_delete;
+ se->handle_fault = simpleseg_handleFault;
+ ss->writable = writable; ss->start = start; ss->len = len;
+ return se;
+}
+
+struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir) {
+ struct segment_map *sm = kmalloc(sizeof(struct segment_map));
+ sm->start = ((struct simpleseg*)(seg->seg_data))->start;
+ sm->len = ((struct simpleseg*)(seg->seg_data))->len;
+ return sm;
+}
+
+void simpleseg_unmap(struct segment_map* sm) {
+ size_t i;
+ for (i = sm->start; i < sm->start + sm->len; i += 0x1000) {
+ page_unmapFree(pagedir_getPage(sm->pagedir, i, 0));
+ }
+}
+
+int simpleseg_handleFault(struct segment_map* sm, size_t addr, int write) {
+ struct simpleseg *ss = sm->seg->seg_data;
+ if (write && !ss->writable) return 1;
+ addr &= 0xFFFFF000;
+ struct page *p = pagedir_getPage(sm->pagedir, addr, 1);
+ if (p->frame != 0) return 1;
+ page_map(p, frame_alloc(), 1, ss->writable);
+ return 0;
+}
+
+void simpleseg_delete(struct segment* seg) {
+}
diff --git a/src/kernel/mem/seg.h b/src/kernel/mem/seg.h
new file mode 100644
index 0000000..022d38e
--- /dev/null
+++ b/src/kernel/mem/seg.h
@@ -0,0 +1,40 @@
+#ifndef DEF_SEG_H
+#define DEF_SEG_H
+
+#include "paging.h"
+
+struct segment_map;
+struct segment {
+ void* seg_data;
+ int mappings;
+
+ struct segment_map* (*map)(struct segment* seg, struct page_directory* pagedir);
+ void (*unmap)(struct segment_map*);
+ void (*delete)(struct segment* seg);
+ int (*handle_fault)(struct segment_map* map, size_t addr, int write); //0 if ok, 1 if segfault
+};
+
+struct segment_map {
+ struct segment* seg;
+ struct page_directory* pagedir;
+ size_t start, len;
+ struct segment_map *next;
+};
+
+struct segment_map *seg_map(struct segment* seg, struct page_directory* pagedir);
+void seg_unmap(struct segment_map* map);
+
+/// ************************************* SIMPLESEG stuff *****************
+
+struct simpleseg {
+ int writable;
+ size_t start, len;
+};
+
+struct segment* simpleseg_make(size_t start, size_t len, int writable);
+struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir);
+void simpleseg_unmap(struct segment_map*);
+void simpleseg_delete(struct segment *seg);
+int simpleseg_handleFault(struct segment_map* map, size_t addr, int write);
+
+#endif
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