diff options
37 files changed, 2059 insertions, 0 deletions
diff --git a/Grapes.fl.img b/Grapes.fl.img Binary files differnew file mode 100644 index 0000000..b0e4c18 --- /dev/null +++ b/Grapes.fl.img diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..94f5ff7 --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +.PHONY: clean, mrproper, Init.rfs, floppy, commit + +Projects = stem + +Kernel = src/stem/stem.elf +Floppy = Grapes.fl.img + +all: + for p in $(Projects); do \ + echo "=> Building $$p"; \ + make -C src/$$p -s; \ + done + +rebuild: mrproper all + +clean: + for p in $(Projects); do \ + echo "=> Building $$p"; \ + make -C src/$$p clean -s; \ + done + +mrproper: + for p in $(Projects); do \ + echo "=> Building $$p"; \ + make -C src/$$p mrproper -s; \ + done + +commit: mrproper + git add . + git commit -a; exit 0 + git push github + git push home + +floppy: + mkdir mnt; exit 0 + sudo mount $(Floppy) mnt -o loop + sudo ./copy_fdd.sh + sleep 0.3 + sudo umount mnt + + +bochs: all floppy + bochs -f bochs.cfg + +qemu: all floppy + qemu -fda $(Floppy) -m 8 diff --git a/bochs.cfg b/bochs.cfg new file mode 100644 index 0000000..c46bba8 --- /dev/null +++ b/bochs.cfg @@ -0,0 +1,46 @@ +# configuration file generated by Bochs +config_interface: textconfig +display_library: x +megs: 8 +romimage: file="/usr/share/bochs/BIOS-bochs-latest" +vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest" +boot: floppy +floppy_bootsig_check: disabled=0 +floppya: 1_44="Grapes.fl.img", status=inserted +# no floppyb +ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 +ata1: enabled=1, ioaddr1=0x170, ioaddr2=0x370, irq=15 +ata2: enabled=0 +ata3: enabled=0 +parport1: enabled=1, file="" +parport2: enabled=0 +com1: enabled=1, mode=null, dev="" +com2: enabled=0 +com3: enabled=0 +com4: enabled=0 +i440fxsupport: enabled=0 +vga_update_interval: 40000 +vga: extension=vbe +cpu: count=1, ips=2000000, reset_on_triple_fault=1 +text_snapshot_check: enabled=0 +private_colormap: enabled=0 +clock: sync=none, time0=local +# no cmosimage +ne2k: enabled=0 +pnic: enabled=0 +sb16: enabled=0 +# no loader +log: - +logprefix: %t%e%d +debugger_log: - +panic: action=ask +error: action=report +info: action=report +debug: action=ignore +pass: action=fatal +keyboard_type: mf +keyboard_serial_delay: 250 +keyboard_paste_delay: 100000 +keyboard_mapping: enabled=1, map=/usr/share/bochs/keymaps/x11-pc-fr.map +user_shortcut: keys=none +mouse: enabled=0, type=ps2 diff --git a/copy_fdd.sh b/copy_fdd.sh new file mode 100755 index 0000000..d6514d9 --- /dev/null +++ b/copy_fdd.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +# We assume mnt/ is the directory where the image is mounted, and src/ is the directory with all the compiled files + +# Update GRUB's menu.cfg +cp menu_fdd.cfg mnt/boot/menu.cfg + +# copy kernel +cp src/stem/stem.elf mnt + +#echo "*** Launching a BASH shell, if you want to do any maintenance ***" +#bash || exit 0 diff --git a/menu_fdd.cfg b/menu_fdd.cfg new file mode 100644 index 0000000..f5dd85c --- /dev/null +++ b/menu_fdd.cfg @@ -0,0 +1,2 @@ +title Grapes +kernel /stem.elf 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(®s) == 0) || regs.int_no != 14) { + if (tasking_handleException(®s) == 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](®s); + } 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 |