summaryrefslogtreecommitdiff
path: root/src/stem
diff options
context:
space:
mode:
authorAlexis211 <alexis211@gmail.com>2010-01-25 18:38:43 +0100
committerAlexis211 <alexis211@gmail.com>2010-01-25 18:38:43 +0100
commit4ae83c83f34759172e9c575c8ac875011bfaff2d (patch)
tree26ec6c665cbada6e413bd31e34c60d7c2bbb41c3 /src/stem
downloadTCE-4ae83c83f34759172e9c575c8ac875011bfaff2d.tar.gz
TCE-4ae83c83f34759172e9c575c8ac875011bfaff2d.zip
First commit
Diffstat (limited to 'src/stem')
-rw-r--r--src/stem/Makefile35
-rw-r--r--src/stem/gdt.c36
-rw-r--r--src/stem/gdt.h23
-rw-r--r--src/stem/heap.c224
-rw-r--r--src/stem/heap.h27
-rw-r--r--src/stem/idt.c178
-rw-r--r--src/stem/idt.h33
-rw-r--r--src/stem/idt_.asm143
-rw-r--r--src/stem/kmain.c44
-rw-r--r--src/stem/lib/bitset.c34
-rw-r--r--src/stem/lib/bitset.h19
-rw-r--r--src/stem/lib/stdlib.c31
-rw-r--r--src/stem/lib/stdlib.h12
-rw-r--r--src/stem/link.ld32
-rw-r--r--src/stem/loader_.asm63
-rw-r--r--src/stem/mem.c94
-rw-r--r--src/stem/mem.h17
-rw-r--r--src/stem/monitor.c90
-rw-r--r--src/stem/monitor.h12
-rw-r--r--src/stem/multiboot.h64
-rw-r--r--src/stem/paging.c121
-rw-r--r--src/stem/paging.h42
-rw-r--r--src/stem/stem.map286
-rw-r--r--src/stem/sys.c41
-rw-r--r--src/stem/sys.h17
-rw-r--r--src/stem/task.c123
-rw-r--r--src/stem/task.h41
-rw-r--r--src/stem/task_.asm10
-rw-r--r--src/stem/timer.c36
-rw-r--r--src/stem/timer.h10
-rw-r--r--src/stem/types.h15
31 files changed, 1953 insertions, 0 deletions
diff --git a/src/stem/Makefile b/src/stem/Makefile
new file mode 100644
index 0000000..94e2000
--- /dev/null
+++ b/src/stem/Makefile
@@ -0,0 +1,35 @@
+
+CC = gcc
+CFLAGS = -nostdlib -nostartfiles -nodefaultlibs -fno-builtin -fno-stack-protector -Wall -Wextra
+
+LD = ld
+LDFLAGS = -T link.ld
+
+ASM = nasm
+AFLAGS = -f elf
+
+OBJECTS = loader_.o kmain.o sys.o \
+ monitor.o timer.o \
+ idt.o idt_.o task.o task_.o\
+ lib/stdlib.o lib/bitset.o \
+ mem.o paging.o gdt.o heap.o
+OUT = stem.elf
+
+all: $(OBJECTS)
+ echo "* Linking $(OUT)..."
+ $(LD) $(LDFLAGS) $(OBJECTS) -o $(OUT) -Map stem.map
+
+clean:
+ rm *.o || exit 0
+ rm $(OBJECTS) || exit 0
+
+mrproper: clean
+ rm $(OUT)
+
+%.o: %.asm
+ echo "* Compiling $<..."
+ $(ASM) $(AFLAGS) -o $@ $<
+
+%.o: %.c
+ echo "* Compiling $<..."
+ $(CC) -c $< -o $@ $(CFLAGS)
diff --git a/src/stem/gdt.c b/src/stem/gdt.c
new file mode 100644
index 0000000..00a42ca
--- /dev/null
+++ b/src/stem/gdt.c
@@ -0,0 +1,36 @@
+#include "gdt.h"
+#include "lib/stdlib.h"
+#include "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/stem/gdt.h b/src/stem/gdt.h
new file mode 100644
index 0000000..5a3f7b2
--- /dev/null
+++ b/src/stem/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/stem/heap.c b/src/stem/heap.c
new file mode 100644
index 0000000..b6d2cd4
--- /dev/null
+++ b/src/stem/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/stem/heap.h b/src/stem/heap.h
new file mode 100644
index 0000000..39ba37e
--- /dev/null
+++ b/src/stem/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/stem/idt.c b/src/stem/idt.c
new file mode 100644
index 0000000..6ad5b23
--- /dev/null
+++ b/src/stem/idt.c
@@ -0,0 +1,178 @@
+#include "idt.h"
+#include "monitor.h"
+#include "paging.h"
+#include "sys.h"
+#include "task.h"
+
+#include "lib/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 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();
+}
+
+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_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/stem/idt.h b/src/stem/idt.h
new file mode 100644
index 0000000..a185c9e
--- /dev/null
+++ b/src/stem/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/stem/idt_.asm b/src/stem/idt_.asm
new file mode 100644
index 0000000..b73f7a5
--- /dev/null
+++ b/src/stem/idt_.asm
@@ -0,0 +1,143 @@
+; 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
+
+;************************************************************************************
+
+%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
+
+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
diff --git a/src/stem/kmain.c b/src/stem/kmain.c
new file mode 100644
index 0000000..6fab4ed
--- /dev/null
+++ b/src/stem/kmain.c
@@ -0,0 +1,44 @@
+#include "types.h"
+#include "multiboot.h"
+#include "monitor.h"
+#include "idt.h"
+#include "gdt.h"
+#include "paging.h"
+#include "mem.h"
+#include "sys.h"
+#include "timer.h"
+#include "task.h"
+
+void kmain_othertask(void *data) {
+ while(1) monitor_write("2task ");
+}
+
+void kmain_stage2(void *data) {
+ sti();
+ thread_new(current_thread->process, kmain_othertask, 0);
+ while (1) monitor_write("TASK1 ");
+}
+
+void kmain(struct multiboot_info_t* mbd, int32_t magic) {
+ size_t totalRam = 0;
+
+ mem_placementAddr = (size_t)&end;
+
+ monitor_clear();
+
+ if (magic != MULTIBOOT_BOOTLOADER_MAGIC) {
+ PANIC("wrong multiboot magic number.");
+ }
+
+ monitor_write("Grapes::Stem is 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(kmain_stage2, 0);
+}
diff --git a/src/stem/lib/bitset.c b/src/stem/lib/bitset.c
new file mode 100644
index 0000000..c13a24d
--- /dev/null
+++ b/src/stem/lib/bitset.c
@@ -0,0 +1,34 @@
+#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;
+ }
+ }
+ }
+ }
+}
+
diff --git a/src/stem/lib/bitset.h b/src/stem/lib/bitset.h
new file mode 100644
index 0000000..e3fe078
--- /dev/null
+++ b/src/stem/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/stem/lib/stdlib.c b/src/stem/lib/stdlib.c
new file mode 100644
index 0000000..904126e
--- /dev/null
+++ b/src/stem/lib/stdlib.c
@@ -0,0 +1,31 @@
+#include "stdlib.h"
+
+void *memcpy(void *dest, const void *src, int count) {
+ int i;
+ uint8_t *d = (uint8_t*)dest, *s = (uint8_t*)src;
+ for (i = 0; i < count; i++) {
+ d[i] = s[i];
+ }
+ return dest;
+}
+
+uint8_t *memset(uint8_t *dest, uint8_t val, int count) {
+ int i;
+ for (i = 0; i < count; i++) {
+ dest[i] = val;
+ }
+}
+
+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/stem/lib/stdlib.h b/src/stem/lib/stdlib.h
new file mode 100644
index 0000000..a6d8f48
--- /dev/null
+++ b/src/stem/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/stem/link.ld b/src/stem/link.ld
new file mode 100644
index 0000000..1ce17cf
--- /dev/null
+++ b/src/stem/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/stem/loader_.asm b/src/stem/loader_.asm
new file mode 100644
index 0000000..e1031b4
--- /dev/null
+++ b/src/stem/loader_.asm
@@ -0,0 +1,63 @@
+[GLOBAL loader] ; making entry point visible to linker
+[EXTERN kmain] ; kmain is defined in kmain.c
+
+STACKSIZE equ 0x4000 ; that's 16k.
+
+; 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, stack+STACKSIZE ; 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:
+
+[section .bss]
+align 32
+stack:
+ resb STACKSIZE ; reserve 16k stack on a quadword boundary
diff --git a/src/stem/mem.c b/src/stem/mem.c
new file mode 100644
index 0000000..babe079
--- /dev/null
+++ b/src/stem/mem.c
@@ -0,0 +1,94 @@
+#include "mem.h"
+#include "sys.h"
+#include "paging.h"
+#include "heap.h"
+#include "monitor.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), i, 0, 0);
+ } 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/stem/mem.h b/src/stem/mem.h
new file mode 100644
index 0000000..1dcf463
--- /dev/null
+++ b/src/stem/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/stem/monitor.c b/src/stem/monitor.c
new file mode 100644
index 0000000..8c4744a
--- /dev/null
+++ b/src/stem/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/stem/monitor.h b/src/stem/monitor.h
new file mode 100644
index 0000000..3abe072
--- /dev/null
+++ b/src/stem/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/stem/multiboot.h b/src/stem/multiboot.h
new file mode 100644
index 0000000..908274c
--- /dev/null
+++ b/src/stem/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/stem/paging.c b/src/stem/paging.c
new file mode 100644
index 0000000..bf3d8c4
--- /dev/null
+++ b/src/stem/paging.c
@@ -0,0 +1,121 @@
+#include "paging.h"
+#include "lib/bitset.h"
+#include "lib/stdlib.h"
+#include "monitor.h"
+#include "mem.h"
+#include "sys.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->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] = 9;
+ 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));
+}
+
+uint32_t paging_fault(struct registers *regs) {
+ size_t addr;
+ asm volatile("mov %%cr2, %0" : "=r"(addr));
+ monitor_write("PageFault ");
+ 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");
+ PANIC("Page fault");
+ 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);
+ 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/stem/paging.h b/src/stem/paging.h
new file mode 100644
index 0000000..87ba183
--- /dev/null
+++ b/src/stem/paging.h
@@ -0,0 +1,42 @@
+#ifndef DEF_PAGING_H
+#define DEF_PAGING_H
+
+#include "types.h"
+#include "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 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
+};
+
+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 *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
+
+#endif
diff --git a/src/stem/stem.map b/src/stem/stem.map
new file mode 100644
index 0000000..5967f1a
--- /dev/null
+++ b/src/stem/stem.map
@@ -0,0 +1,286 @@
+
+Allocating common symbols
+Common symbol size file
+
+idt_ptr 0x6 idt.o
+mem_placementAddr 0x4 mem.o
+idt_entries 0x800 idt.o
+current_pagedir 0x4 paging.o
+kernel_pagedir 0x4 paging.o
+
+Memory Configuration
+
+Name Origin Length Attributes
+*default* 0x00000000 0xffffffff
+
+Linker script and memory map
+
+ 0x00100000 . = 0x100000
+
+.setup 0x00100000 0x3a
+ *(.setup)
+ .setup 0x00100000 0x3a loader_.o
+ 0x00100000 loader
+ 0xe010003a . = (. + 0xe0000000)
+
+.text 0xe0100040 0x29b8 load address 0x00100040
+ *(.text)
+ .text 0xe0100040 0x25 loader_.o
+ *fill* 0xe0100065 0x3 00
+ .text 0xe0100068 0xef kmain.o
+ 0xe0100068 kmain_othertask
+ 0xe010007c kmain_stage2
+ 0xe01000b4 kmain
+ *fill* 0xe0100157 0x1 00
+ .text 0xe0100158 0xed sys.o
+ 0xe0100158 outb
+ 0xe0100176 outw
+ 0xe0100196 inb
+ 0xe01001b3 inw
+ 0xe01001d2 panic
+ 0xe0100216 cli
+ 0xe0100229 sti
+ *fill* 0xe0100245 0x3 00
+ .text 0xe0100248 0x310 monitor.o
+ 0xe0100359 monitor_put
+ 0xe0100465 monitor_clear
+ 0xe01004c2 monitor_write
+ 0xe01004eb monitor_writeHex
+ .text 0xe0100558 0x104 timer.o
+ 0xe0100558 timer_callback
+ 0xe0100590 timer_uptime
+ 0xe010059a timer_time
+ 0xe01005d1 timer_init
+ .text 0xe010065c 0x9bb idt.o
+ 0xe010065c idt_isrHandler
+ 0xe01006f4 idt_irqHandler
+ 0xe01007fc idt_init
+ 0xe0101005 idt_handleIrq
+ *fill* 0xe0101017 0x9 00
+ .text 0xe0101020 0x259 idt_.o
+ 0xe0101020 gdt_flush
+ 0xe010103d idt_flush
+ 0xe01010a5 isr0
+ 0xe01010af isr1
+ 0xe01010b9 isr2
+ 0xe01010c3 isr3
+ 0xe01010cd isr4
+ 0xe01010d7 isr5
+ 0xe01010e1 isr6
+ 0xe01010eb isr7
+ 0xe01010f5 isr8
+ 0xe01010fd isr9
+ 0xe0101107 isr10
+ 0xe010110f isr11
+ 0xe0101117 isr12
+ 0xe010111f isr13
+ 0xe0101127 isr14
+ 0xe010112f isr15
+ 0xe0101139 isr16
+ 0xe0101143 isr17
+ 0xe010114d isr18
+ 0xe0101157 isr19
+ 0xe0101161 isr20
+ 0xe010116b isr21
+ 0xe0101175 isr22
+ 0xe010117f isr23
+ 0xe0101189 isr24
+ 0xe0101193 isr25
+ 0xe010119d isr26
+ 0xe01011a7 isr27
+ 0xe01011b1 isr28
+ 0xe01011bb isr29
+ 0xe01011c5 isr30
+ 0xe01011cf isr31
+ 0xe01011d9 irq0
+ 0xe01011e3 irq1
+ 0xe01011ed irq2
+ 0xe01011f7 irq3
+ 0xe0101201 irq4
+ 0xe010120b irq5
+ 0xe0101215 irq6
+ 0xe010121f irq7
+ 0xe0101229 irq8
+ 0xe0101233 irq9
+ 0xe010123d irq10
+ 0xe0101247 irq11
+ 0xe0101251 irq12
+ 0xe010125b irq13
+ 0xe0101265 irq14
+ 0xe010126f irq15
+ *fill* 0xe0101279 0x3 00
+ .text 0xe010127c 0x2e8 task.o
+ 0xe010127c tasking_init
+ 0xe010136f tasking_switch
+ 0xe0101401 tasking_handleException
+ 0xe0101481 thread_new
+ *fill* 0xe0101564 0xc 00
+ .text 0xe0101570 0xa task_.o
+ 0xe0101570 read_eip
+ 0xe0101573 task_idle
+ *fill* 0xe010157a 0x6 00
+ .text 0xe0101580 0x128 lib/stdlib.o
+ 0xe0101580 memcpy
+ 0xe01015de memset
+ 0xe0101621 memsetw
+ 0xe0101670 strlen
+ *fill* 0xe01016a8 0x18 00
+ .text 0xe01016c0 0x189 lib/bitset.o
+ 0xe01016c0 bitset_set
+ 0xe0101700 bitset_clear
+ 0xe0101743 bitset_test
+ 0xe0101788 bitset_firstFree
+ *fill* 0xe0101849 0x3 00
+ .text 0xe010184c 0x29f mem.o
+ 0xe01019b2 kmalloc_page
+ 0xe01019f9 kfree_page
+ 0xe0101a34 kheap_init
+ 0xe0101a89 kmalloc
+ 0xe0101ac7 kfree
+ *fill* 0xe0101aeb 0x1 00
+ .text 0xe0101aec 0x513 paging.o
+ 0xe0101aec frame_alloc
+ 0xe0101b19 frame_free
+ 0xe0101b34 paging_init
+ 0xe0101ccc paging_cleanup
+ 0xe0101d27 pagedir_switch
+ 0xe0101d56 paging_fault
+ 0xe0101e31 pagedir_getPage
+ 0xe0101f10 page_map
+ 0xe0101f98 page_unmap
+ 0xe0101fbb page_unmapFree
+ *fill* 0xe0101fff 0x1 00
+ .text 0xe0102000 0x19f gdt.o
+ 0xe010208f gdt_init
+ *fill* 0xe010219f 0x1 00
+ .text 0xe01021a0 0x858 heap.o
+ 0xe0102330 heap_create
+ 0xe0102703 heap_alloc
+ 0xe0102864 heap_free
+
+.iplt 0xe01029f8 0x0 load address 0x001029f8
+ .iplt 0x00000000 0x0 loader_.o
+
+.rodata 0xe0103000 0x1aa load address 0x00103000
+ *(.rodata)
+ .rodata 0xe0103000 0x4d kmain.o
+ .rodata 0xe010304d 0x2c sys.o
+ .rodata 0xe0103079 0xf timer.o
+ .rodata 0xe0103088 0x73 idt.o
+ .rodata 0xe01030fb 0x12 task.o
+ .rodata 0xe010310d 0x10 mem.o
+ .rodata 0xe010311d 0x85 paging.o
+ .rodata 0xe01031a2 0x8 gdt.o
+
+.rel.dyn 0xe01031ac 0x0 load address 0x001031aa
+ .rel.iplt 0x00000000 0x0 loader_.o
+ .rel.text 0x00000000 0x0 loader_.o
+
+.data 0xe0104000 0x20 load address 0x00104000
+ *(.data)
+ .data 0xe0104000 0x0 kmain.o
+ .data 0xe0104000 0x4 sys.o
+ .data 0xe0104004 0x4 monitor.o
+ .data 0xe0104008 0x0 timer.o
+ .data 0xe0104008 0x0 idt.o
+ .data 0xe0104008 0x4 task.o
+ 0xe0104008 nextpid
+ *fill* 0xe010400c 0x14 00
+ .data 0xe0104020 0x0 lib/stdlib.o
+ .data 0xe0104020 0x0 lib/bitset.o
+ .data 0xe0104020 0x0 mem.o
+ .data 0xe0104020 0x0 paging.o
+ .data 0xe0104020 0x0 gdt.o
+ .data 0xe0104020 0x0 heap.o
+
+.igot.plt 0xe0104020 0x0 load address 0x00104020
+ .igot.plt 0x00000000 0x0 loader_.o
+
+.bss 0xe0104020 0x4950 load address 0x00104020
+ 0xe0104020 sbss = .
+ *(COMMON)
+ COMMON 0xe0104020 0x820 idt.o
+ 0xe0104020 idt_ptr
+ 0xe0104040 idt_entries
+ COMMON 0xe0104840 0x4 mem.o
+ 0xe0104840 mem_placementAddr
+ COMMON 0xe0104844 0x8 paging.o
+ 0xe0104844 current_pagedir
+ 0xe0104848 kernel_pagedir
+ *(.bss)
+ .bss 0xe010484c 0x4000 loader_.o
+ .bss 0xe010884c 0x0 kmain.o
+ .bss 0xe010884c 0x0 sys.o
+ .bss 0xe010884c 0x8 monitor.o
+ .bss 0xe0108854 0xc timer.o
+ .bss 0xe0108860 0x40 idt.o
+ .bss 0xe01088a0 0xc task.o
+ 0xe01088a0 processes
+ 0xe01088a4 threads
+ 0xe01088a8 current_thread
+ *fill* 0xe01088ac 0x14 00
+ .bss 0xe01088c0 0x0 lib/stdlib.o
+ .bss 0xe01088c0 0x0 lib/bitset.o
+ .bss 0xe01088c0 0x60 mem.o
+ 0xe01088c0 freepagecount
+ .bss 0xe0108920 0x8 paging.o
+ *fill* 0xe0108928 0x18 00
+ .bss 0xe0108940 0x2e gdt.o
+ *fill* 0xe010896e 0x2 00
+ .bss 0xe0108970 0x0 heap.o
+ 0xe0108970 ebss = .
+ 0xe0108970 end = .
+ 0xe0108970 _end = .
+ 0xe0108970 __end = .
+LOAD loader_.o
+LOAD kmain.o
+LOAD sys.o
+LOAD monitor.o
+LOAD timer.o
+LOAD idt.o
+LOAD idt_.o
+LOAD task.o
+LOAD task_.o
+LOAD lib/stdlib.o
+LOAD lib/bitset.o
+LOAD mem.o
+LOAD paging.o
+LOAD gdt.o
+LOAD heap.o
+OUTPUT(stem.elf elf32-i386)
+
+.comment 0x00000000 0x27
+ .comment 0x00000000 0x27 kmain.o
+ 0x28 (size before relaxing)
+ .comment 0x00000000 0x28 sys.o
+ .comment 0x00000000 0x28 monitor.o
+ .comment 0x00000000 0x28 timer.o
+ .comment 0x00000000 0x28 idt.o
+ .comment 0x00000000 0x28 task.o
+ .comment 0x00000000 0x28 mem.o
+ .comment 0x00000000 0x28 paging.o
+ .comment 0x00000000 0x28 gdt.o
+ .comment 0x00000000 0x28 heap.o
+
+.note.GNU-stack
+ 0x00000000 0x0
+ .note.GNU-stack
+ 0x00000000 0x0 kmain.o
+ .note.GNU-stack
+ 0x00000000 0x0 sys.o
+ .note.GNU-stack
+ 0x00000000 0x0 monitor.o
+ .note.GNU-stack
+ 0x00000000 0x0 timer.o
+ .note.GNU-stack
+ 0x00000000 0x0 idt.o
+ .note.GNU-stack
+ 0x00000000 0x0 task.o
+ .note.GNU-stack
+ 0x00000000 0x0 mem.o
+ .note.GNU-stack
+ 0x00000000 0x0 paging.o
+ .note.GNU-stack
+ 0x00000000 0x0 gdt.o
+ .note.GNU-stack
+ 0x00000000 0x0 heap.o
diff --git a/src/stem/sys.c b/src/stem/sys.c
new file mode 100644
index 0000000..71d1c31
--- /dev/null
+++ b/src/stem/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(">> 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_locks--;
+ if (if_locks == 0) asm volatile("sti");
+}
diff --git a/src/stem/sys.h b/src/stem/sys.h
new file mode 100644
index 0000000..76e3560
--- /dev/null
+++ b/src/stem/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/stem/task.c b/src/stem/task.c
new file mode 100644
index 0000000..874f22d
--- /dev/null
+++ b/src/stem/task.c
@@ -0,0 +1,123 @@
+#include "task.h"
+#include "sys.h"
+#include "mem.h"
+#include "timer.h"
+#include "monitor.h"
+
+#define KSTACKSIZE 0x8000
+
+//From task_.asm
+extern uint32_t read_eip();
+extern void task_idle(void*);
+
+static uint32_t thread_runnable(struct thread *th);
+
+uint32_t nextpid = 1;
+
+struct process *processes = 0;
+struct thread *threads = 0, *current_thread = 0;
+
+void tasking_init(thread_entry whereToGo, void *data) {
+ cli();
+ struct process *pr = kmalloc(sizeof(struct process)); //This process must be hidden to users
+ pr->pid = pr->uid = 0;
+ pr->parent = pr;
+ pr->pagedir = kernel_pagedir;
+ pr->next = 0;
+ current_thread = 0;
+ thread_new(pr, task_idle, 0);
+ thread_new(pr, whereToGo, data);
+ sti();
+ monitor_write("Tasking starting\n");
+ tasking_switch();
+}
+
+static struct thread *thread_next() { //NOT OPTIMAL : will allocate time slices to idle thread even if busy
+ if (current_thread == 0) current_thread = threads;
+ struct thread *ret = current_thread;
+ while (1) {
+ ret = ret->next;
+ if (ret == 0) ret = threads;
+ if (thread_runnable(ret)) {
+ return ret;
+ }
+ }
+}
+
+void tasking_switch() {
+ if (threads == 0) return; //no tasking yet
+ 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));
+}
+
+uint32_t tasking_handleException(struct registers *regs) {
+ if (threads == 0) return 0; //No tasking yet
+ return 0;
+}
+
+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);
+ asm volatile("sti");
+ entry_point(data);
+ asm volatile("int $64");
+}
+
+void thread_new(struct process *proc, thread_entry entry_point, void *data) {
+ struct thread *t = kmalloc(sizeof(struct thread));
+ t->process = proc;
+ 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;
+ }
+}
+
diff --git a/src/stem/task.h b/src/stem/task.h
new file mode 100644
index 0000000..3fec9ea
--- /dev/null
+++ b/src/stem/task.h
@@ -0,0 +1,41 @@
+#ifndef DEF_TASK_H
+#define DEF_TASK_H
+
+#include "types.h"
+#include "paging.h"
+#include "idt.h"
+
+struct process {
+ uint32_t pid, uid;
+ struct process *parent;
+ struct page_directory *pagedir;
+
+ struct process *next; //Forms a linked list
+};
+
+#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)
+
+typedef void (*thread_entry)(void*);
+
+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(thread_entry whereToGo, void *data);
+void tasking_switch();
+uint32_t tasking_handleException(struct registers *regs);
+
+void thread_new(struct process *proc, thread_entry entry_point, void *data);
+
+#endif
diff --git a/src/stem/task_.asm b/src/stem/task_.asm
new file mode 100644
index 0000000..ae45c68
--- /dev/null
+++ b/src/stem/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/stem/timer.c b/src/stem/timer.c
new file mode 100644
index 0000000..10651ab
--- /dev/null
+++ b/src/stem/timer.c
@@ -0,0 +1,36 @@
+#include "timer.h"
+#include "idt.h"
+#include "sys.h"
+#include "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/stem/timer.h b/src/stem/timer.h
new file mode 100644
index 0000000..3ed3009
--- /dev/null
+++ b/src/stem/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
diff --git a/src/stem/types.h b/src/stem/types.h
new file mode 100644
index 0000000..b7b19ab
--- /dev/null
+++ b/src/stem/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