From 277e4af4fa9e80816c809542d792ee6bebb7f202 Mon Sep 17 00:00:00 2001 From: Alex AUVOLAT Date: Fri, 4 May 2012 20:06:37 +0200 Subject: Migration to C++! --- src/common.make | 11 +- src/common/include/stdlib_common.h | 8 + src/common/include/string.h | 8 + src/common/include/types.h | 4 +- src/kernel/config.h | 4 +- src/kernel/core/kmain.c | 79 ------- src/kernel/core/kmain.cpp | 79 +++++++ src/kernel/core/monitor.c | 114 ---------- src/kernel/core/monitor.cpp | 114 ++++++++++ src/kernel/core/sys.c | 73 ------- src/kernel/core/sys.cpp | 73 +++++++ src/kernel/lib/bitset.c | 35 ---- src/kernel/lib/bitset.cpp | 35 ++++ src/kernel/lib/bitset.h | 9 +- src/kernel/lib/cpp.h | 16 ++ src/kernel/lib/std.c | 11 - src/kernel/lib/std.cpp | 12 ++ src/kernel/lib/std.h | 5 + src/kernel/linker/elf.c | 57 ----- src/kernel/linker/elf.cpp | 57 +++++ src/kernel/linker/elf.h | 6 +- src/kernel/mem/_dlmalloc.h | 3 + src/kernel/mem/gdt.c | 64 ------ src/kernel/mem/gdt.cpp | 64 ++++++ src/kernel/mem/mem.c | 137 ------------- src/kernel/mem/mem.cpp | 137 +++++++++++++ src/kernel/mem/mem.h | 12 +- src/kernel/mem/paging.c | 203 ------------------ src/kernel/mem/paging.cpp | 203 ++++++++++++++++++ src/kernel/mem/paging.h | 26 +-- src/kernel/mem/seg.c | 113 ---------- src/kernel/mem/seg.cpp | 113 ++++++++++ src/kernel/mem/seg.h | 24 +-- src/kernel/task/idt.c | 219 -------------------- src/kernel/task/idt.cpp | 223 ++++++++++++++++++++ src/kernel/task/idt.h | 2 +- src/kernel/task/sched.c | 50 ----- src/kernel/task/sched.cpp | 50 +++++ src/kernel/task/sched.h | 4 +- src/kernel/task/syscall.c | 45 ---- src/kernel/task/syscall.cpp | 50 +++++ src/kernel/task/task.c | 410 ------------------------------------ src/kernel/task/task.cpp | 411 +++++++++++++++++++++++++++++++++++++ src/kernel/task/task.h | 29 +-- src/kernel/task/timer.c | 91 -------- src/kernel/task/timer.cpp | 91 ++++++++ 46 files changed, 1823 insertions(+), 1761 deletions(-) delete mode 100644 src/kernel/core/kmain.c create mode 100644 src/kernel/core/kmain.cpp delete mode 100644 src/kernel/core/monitor.c create mode 100644 src/kernel/core/monitor.cpp delete mode 100644 src/kernel/core/sys.c create mode 100644 src/kernel/core/sys.cpp delete mode 100644 src/kernel/lib/bitset.c create mode 100644 src/kernel/lib/bitset.cpp create mode 100644 src/kernel/lib/cpp.h delete mode 100644 src/kernel/lib/std.c create mode 100644 src/kernel/lib/std.cpp delete mode 100644 src/kernel/linker/elf.c create mode 100644 src/kernel/linker/elf.cpp delete mode 100644 src/kernel/mem/gdt.c create mode 100644 src/kernel/mem/gdt.cpp delete mode 100644 src/kernel/mem/mem.c create mode 100644 src/kernel/mem/mem.cpp delete mode 100644 src/kernel/mem/paging.c create mode 100644 src/kernel/mem/paging.cpp delete mode 100644 src/kernel/mem/seg.c create mode 100644 src/kernel/mem/seg.cpp delete mode 100644 src/kernel/task/idt.c create mode 100644 src/kernel/task/idt.cpp delete mode 100644 src/kernel/task/sched.c create mode 100644 src/kernel/task/sched.cpp delete mode 100644 src/kernel/task/syscall.c create mode 100644 src/kernel/task/syscall.cpp delete mode 100644 src/kernel/task/task.c create mode 100644 src/kernel/task/task.cpp delete mode 100644 src/kernel/task/timer.c create mode 100644 src/kernel/task/timer.cpp diff --git a/src/common.make b/src/common.make index 438ff07..5ea9ae9 100644 --- a/src/common.make +++ b/src/common.make @@ -2,11 +2,14 @@ CC = i586-elf-gcc CFLAGS = -nostdlib -nostartfiles -nodefaultlibs -fno-builtin -fno-stack-protector -Wall -Wextra +CCFLAGS = +CXX = i586-elf-g++ +CXXFLAGS = -fno-rtti -fno-exceptions -Werror -Wno-write-strings -Wno-error=unused-parameter LD = i586-elf-ld .PHONY: clean, mrproper -LDFLAGS = +LDFLAGS = -oformat=elf32-i386 ASM = nasm AFLAGS = -f elf @@ -36,4 +39,8 @@ mrproper: clean %.o: %.c echo ""; echo "- $<" - $(CC) -c $< -o $@ $(CFLAGS) + $(CC) -c $< -o $@ $(CFLAGS) $(CCFLAGS) + +%.o: %.cpp + echo ""; echo "- $<" + $(CXX) -c $< -o $@ $(CFLAGS) $(CXXFLAGS) diff --git a/src/common/include/stdlib_common.h b/src/common/include/stdlib_common.h index 80c188f..dc40b96 100644 --- a/src/common/include/stdlib_common.h +++ b/src/common/include/stdlib_common.h @@ -6,9 +6,17 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) +#ifdef __cplusplus +extern "C" { +#endif + void *memcpy(void *dest, const void *src, int count); void *memset(void *dest, int val, int count); uint16_t *memsetw(uint16_t *dest, uint16_t val, int count); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/common/include/string.h b/src/common/include/string.h index a41459e..e6aa86e 100644 --- a/src/common/include/string.h +++ b/src/common/include/string.h @@ -4,6 +4,10 @@ // #include #include +#ifdef __cplusplus +extern "C" { +#endif + int strlen(const char *str); char *strcpy(char *dest, const char *src); // char *strdup(const char *src); // uses malloc, that's bad @@ -11,4 +15,8 @@ char *strchr(const char *str, char c); char *strcat(char *dest, const char *src); int strcmp(const char *s1, const char *s2); +#ifdef __cplusplus +} +#endif + #endif diff --git a/src/common/include/types.h b/src/common/include/types.h index ec24ce5..e7c1a35 100644 --- a/src/common/include/types.h +++ b/src/common/include/types.h @@ -2,7 +2,7 @@ #define DEF_TYPES_H typedef unsigned long long uint64_t; -typedef unsigned int uint32_t; +typedef unsigned long int uint32_t; typedef unsigned short uint16_t; typedef unsigned char uint8_t; typedef long long int64_t; @@ -10,7 +10,7 @@ typedef int int32_t; typedef short int16_t; typedef char int8_t; -typedef unsigned int size_t; +typedef long unsigned int size_t; #define NULL 0 diff --git a/src/kernel/config.h b/src/kernel/config.h index f021d9c..ee6141e 100644 --- a/src/kernel/config.h +++ b/src/kernel/config.h @@ -2,8 +2,8 @@ #define DEF_CONFIG_H #define K_OS_NAME "T/CE" -#define K_OS_VER "0.0.1" -#define K_OS_CODENAME "Nyanyanya" +#define K_OS_VER "0.0.2" +#define K_OS_CODENAME "CPLUSPLUS==\\o/" /* HEAP CODE TO USE : Two kernel heap implementations are available : diff --git a/src/kernel/core/kmain.c b/src/kernel/core/kmain.c deleted file mode 100644 index 8c36b54..0000000 --- a/src/kernel/core/kmain.c +++ /dev/null @@ -1,79 +0,0 @@ -#include -#include - -#include "multiboot.h" -#include "monitor.h" -#include "sys.h" -#include -#include -#include -#include -#include -#include -#include - -/* The kernel's main procedure. This function is called in loader_.asm. - This function calls the initializer functions for all system parts. - It then loads the modules the kernel was given by the bootloader. - This function never returns : once multitasking is started for good, - the execution flow of this function is never returned to. */ -void kmain(struct multiboot_info_t* mbd, int32_t magic) { - ASSERT(magic == MULTIBOOT_BOOTLOADER_MAGIC); - - size_t totalRam = 0; - uint32_t i; - - mem_placementAddr = ((size_t)&end & 0xFFFFF000) + 0x1000; - mbd->cmdline += K_HIGHHALF_ADDR; mbd->mods_addr += K_HIGHHALF_ADDR; - struct module_t *mods = (struct module_t*)mbd->mods_addr; - for (i = 0; i < mbd->mods_count; i++) { - mods[i].mod_start += K_HIGHHALF_ADDR; - mods[i].mod_end += K_HIGHHALF_ADDR; - mods[i].string += K_HIGHHALF_ADDR; - if (mods[i].mod_end > mem_placementAddr) - mem_placementAddr = (mods[i].mod_end & 0xFFFFF000) + 0x1000; - } - - monitor_clear(); - - monitor_write(K_OS_NAME); - monitor_write(" version "); - monitor_write(K_OS_VER); - monitor_write(" codename '"); - monitor_write(K_OS_CODENAME); - monitor_write("' starting up :\n"); - - - idt_init(); - - totalRam = ((mbd->mem_upper + mbd->mem_lower) * 1024); - paging_init(totalRam); - _no_more_ksbrk = 1; - gdt_init(); - paging_cleanup(); - - //kheap_init(); - timer_init(30); - tasking_init(); - - monitor_write("\n\nLoading modules :\n"); - for (i = 0; i < mbd->mods_count; i++) { - monitor_write(" * "); - monitor_write((char*)mods[i].string); - if (elf_check((uint8_t*)mods[i].mod_start)) { - monitor_write(" : Invalid ELF file\n"); - } else { - struct process *pr = elf_exec((uint8_t*)mods[i].mod_start, PL_USER); - if (pr == 0) { - monitor_write(" : Error loading\n"); - } else { - monitor_write(" : OK, pid="); monitor_writeDec(pr->pid); monitor_write("\n"); - } - } - } - - monitor_write("Modules now RULE THE WORLD !\n\n"); - sti(); - schedule(); - PANIC("Should never happen. Something probably went wrong with multitasking."); -} diff --git a/src/kernel/core/kmain.cpp b/src/kernel/core/kmain.cpp new file mode 100644 index 0000000..0a5f2d8 --- /dev/null +++ b/src/kernel/core/kmain.cpp @@ -0,0 +1,79 @@ +#include +#include + +#include "multiboot.h" +#include "monitor.h" +#include "sys.h" +#include +#include +#include +#include +#include +#include +#include + +/* The kernel's main procedure. This function is called in loader_.asm. + This function calls the initializer functions for all system parts. + It then loads the modules the kernel was given by the bootloader. + This function never returns : once multitasking is started for good, + the execution flow of this function is never returned to. */ +extern "C" void kmain(multiboot_info_t* mbd, int32_t magic) { + ASSERT(magic == MULTIBOOT_BOOTLOADER_MAGIC); + + size_t totalRam = 0; + uint32_t i; + + mem_placementAddr = ((size_t)&end & 0xFFFFF000) + 0x1000; + mbd->cmdline += K_HIGHHALF_ADDR; mbd->mods_addr += K_HIGHHALF_ADDR; + module_t *mods = (module_t*)mbd->mods_addr; + for (i = 0; i < mbd->mods_count; i++) { + mods[i].mod_start += K_HIGHHALF_ADDR; + mods[i].mod_end += K_HIGHHALF_ADDR; + mods[i].string += K_HIGHHALF_ADDR; + if (mods[i].mod_end > mem_placementAddr) + mem_placementAddr = (mods[i].mod_end & 0xFFFFF000) + 0x1000; + } + + monitor_clear(); + + monitor_write(K_OS_NAME); + monitor_write(" version "); + monitor_write(K_OS_VER); + monitor_write(" codename '"); + monitor_write(K_OS_CODENAME); + monitor_write("' starting up :\n"); + + + idt_init(); + + totalRam = ((mbd->mem_upper + mbd->mem_lower) * 1024); + paging_init(totalRam); + _no_more_ksbrk = true; + gdt_init(); + paging_cleanup(); + + //kheap_init(); + timer_init(30); + tasking_init(); + + monitor_write("\nLoading modules :\n"); + for (i = 0; i < mbd->mods_count; i++) { + monitor_write(" * "); + monitor_write((char*)mods[i].string); + if (elf_check((uint8_t*)mods[i].mod_start)) { + monitor_write(" : Invalid ELF file\n"); + } else { + process *pr = elf_exec((uint8_t*)mods[i].mod_start, PL_USER); + if (pr == 0) { + monitor_write(" : Error loading\n"); + } else { + monitor_write(" : OK, pid="); monitor_writeDec(pr->pid); monitor_write("\n"); + } + } + } + + monitor_write("Modules now RULE THE WORLD !\n\n"); + sti(); + schedule(); + PANIC("Should never happen. Something probably went wrong with multitasking."); +} diff --git a/src/kernel/core/monitor.c b/src/kernel/core/monitor.c deleted file mode 100644 index ba2a6df..0000000 --- a/src/kernel/core/monitor.c +++ /dev/null @@ -1,114 +0,0 @@ -#include "monitor.h" -#include "sys.h" - -#include "mem/mem.h" - -static int cursor_x = 0, cursor_y = 0; -static uint16_t *video_memory = (uint16_t*)((size_t)K_HIGHHALF_ADDR + 0xB8000); - -static uint8_t attribute = 0x07; // 0 = background = black, 7 = foreground = white - -/* For internal use only. Tells hardware to move the cursor at (cursor_x, cursor_y). */ -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); -} - -/* For internal use only. Scrolls everything up one line. */ -static void scroll() { - uint16_t blank = (attribute << 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; - } -} - -/* Put one character on the screen. This function handles special characters \b, \t, \r and \n. */ -void monitor_put(char c) { - if (c == '\b' && cursor_x) { //Backspace - cursor_x--; - } else if (c == '\t') { //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 << 8); - cursor_x++; - } - if (cursor_x >= 80) { - cursor_x = 0; - cursor_y++; - } - - scroll(); - move_cursor(); -} - -/* Clears the screen and moves cursor to (0,0) (top left corner) */ -void monitor_clear() { - uint16_t blank = (attribute << 8) | 0x20; - - int i; - - for (i = 0; i < 80*25; i++) { - video_memory[i] = blank; - } - - cursor_x = 0; cursor_y = 0; - move_cursor(); -} - -/* Writes a string to the monitor */ -void monitor_write(char *s) { - while (*s) { - monitor_put(*(s++)); - } -} - -/* Writes a number in hexadecimal notation to the monitor */ -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; - } -} - -/* Writes a number in decimal notation to the monitor */ -void monitor_writeDec(uint32_t v) { - if (v == 0) { - monitor_put('0'); - return; - } - - char numbers[] = "0123456789"; - while (v > 0) { - int order = 1, no = 1; - while (v / order > 0) order *= 10; - order /= 10; - monitor_put(numbers[v / order]); - v = v - (v / order * order); - while (v / no > 0) no *= 10; - while (no < order) { - monitor_put('0'); - no *= 10; - } - } -} diff --git a/src/kernel/core/monitor.cpp b/src/kernel/core/monitor.cpp new file mode 100644 index 0000000..ba2a6df --- /dev/null +++ b/src/kernel/core/monitor.cpp @@ -0,0 +1,114 @@ +#include "monitor.h" +#include "sys.h" + +#include "mem/mem.h" + +static int cursor_x = 0, cursor_y = 0; +static uint16_t *video_memory = (uint16_t*)((size_t)K_HIGHHALF_ADDR + 0xB8000); + +static uint8_t attribute = 0x07; // 0 = background = black, 7 = foreground = white + +/* For internal use only. Tells hardware to move the cursor at (cursor_x, cursor_y). */ +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); +} + +/* For internal use only. Scrolls everything up one line. */ +static void scroll() { + uint16_t blank = (attribute << 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; + } +} + +/* Put one character on the screen. This function handles special characters \b, \t, \r and \n. */ +void monitor_put(char c) { + if (c == '\b' && cursor_x) { //Backspace + cursor_x--; + } else if (c == '\t') { //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 << 8); + cursor_x++; + } + if (cursor_x >= 80) { + cursor_x = 0; + cursor_y++; + } + + scroll(); + move_cursor(); +} + +/* Clears the screen and moves cursor to (0,0) (top left corner) */ +void monitor_clear() { + uint16_t blank = (attribute << 8) | 0x20; + + int i; + + for (i = 0; i < 80*25; i++) { + video_memory[i] = blank; + } + + cursor_x = 0; cursor_y = 0; + move_cursor(); +} + +/* Writes a string to the monitor */ +void monitor_write(char *s) { + while (*s) { + monitor_put(*(s++)); + } +} + +/* Writes a number in hexadecimal notation to the monitor */ +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; + } +} + +/* Writes a number in decimal notation to the monitor */ +void monitor_writeDec(uint32_t v) { + if (v == 0) { + monitor_put('0'); + return; + } + + char numbers[] = "0123456789"; + while (v > 0) { + int order = 1, no = 1; + while (v / order > 0) order *= 10; + order /= 10; + monitor_put(numbers[v / order]); + v = v - (v / order * order); + while (v / no > 0) no *= 10; + while (no < order) { + monitor_put('0'); + no *= 10; + } + } +} diff --git a/src/kernel/core/sys.c b/src/kernel/core/sys.c deleted file mode 100644 index 2c2372d..0000000 --- a/src/kernel/core/sys.c +++ /dev/null @@ -1,73 +0,0 @@ -#include "sys.h" -#include "monitor.h" - -#include "mem/mem.h" - -/* These four functions are wrappers around ASM operations. - These functions are used when comunicating with the system hardware. */ - -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 stack_trace(size_t bp) { - uint32_t *stack = (uint32_t*)bp, i; - for (i = 0; i < 5 && stack > K_HIGHHALF_ADDR && stack < (bp + 0x8000); i++) { - monitor_write("| "); monitor_writeHex(stack); - monitor_write("\tnext:"); monitor_writeHex(stack[0]); monitor_write("\t\tret:"); monitor_writeHex(stack[1]); - monitor_write("\n"); - stack = (uint32_t*)stack[0]; - } -} - -/* For internal use only. Used by panic and panic_assert. */ -static void panic_do(char* file, int line) { - asm volatile("cli;"); - monitor_write("\n File:\t\t"); monitor_write(file); monitor_put(':'); monitor_writeDec(line); - monitor_write("\nTrace:\n"); - size_t bp; asm volatile("mov %%ebp,%0" : "=r"(bp)); stack_trace(bp); - monitor_write("\n\t\tSystem halted -_-'"); - asm volatile("hlt"); -} - -/* These functions stop the system, reporting an error message, because something bad happenned. */ -void panic(char* message, char* file, int line) { - monitor_write("\nPANIC:\t\t"); monitor_write(message); - panic_do(file, line); -} - -void panic_assert(char* assertion, char* file, int line) { - monitor_write("\nASSERT FAILED:\t"); monitor_write(assertion); - panic_do(file, line); -} - -/* Global system mutex. See comments in sys.h. */ - -static uint32_t if_locks = 1; - -void cli() { - asm volatile("cli"); - if_locks++; -} - -void sti() { - if (if_locks > 0) if_locks--; - if (if_locks == 0) asm volatile("sti"); -} diff --git a/src/kernel/core/sys.cpp b/src/kernel/core/sys.cpp new file mode 100644 index 0000000..d95b678 --- /dev/null +++ b/src/kernel/core/sys.cpp @@ -0,0 +1,73 @@ +#include "sys.h" +#include "monitor.h" + +#include "mem/mem.h" + +/* These four functions are wrappers around ASM operations. + These functions are used when comunicating with the system hardware. */ + +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 stack_trace(size_t bp) { + uint32_t *stack = (uint32_t*)bp, i; + for (i = 0; i < 5 && (size_t)stack > K_HIGHHALF_ADDR && (size_t)stack < (bp + 0x8000); i++) { + monitor_write("| "); monitor_writeHex((size_t)stack); + monitor_write("\tnext:"); monitor_writeHex(stack[0]); monitor_write("\t\tret:"); monitor_writeHex(stack[1]); + monitor_write("\n"); + stack = (uint32_t*)stack[0]; + } +} + +/* For internal use only. Used by panic and panic_assert. */ +static void panic_do(char* file, int line) { + asm volatile("cli;"); + monitor_write("\n File:\t\t"); monitor_write(file); monitor_put(':'); monitor_writeDec(line); + monitor_write("\nTrace:\n"); + size_t bp; asm volatile("mov %%ebp,%0" : "=r"(bp)); stack_trace(bp); + monitor_write("\n\t\tSystem halted -_-'"); + asm volatile("hlt"); +} + +/* These functions stop the system, reporting an error message, because something bad happenned. */ +void panic(char* message, char* file, int line) { + monitor_write("\nPANIC:\t\t"); monitor_write(message); + panic_do(file, line); +} + +void panic_assert(char* assertion, char* file, int line) { + monitor_write("\nASSERT FAILED:\t"); monitor_write(assertion); + panic_do(file, line); +} + +/* Global system mutex. See comments in sys.h. */ + +static uint32_t if_locks = 1; + +void cli() { + asm volatile("cli"); + if_locks++; +} + +void sti() { + if (if_locks > 0) if_locks--; + if (if_locks == 0) asm volatile("sti"); +} diff --git a/src/kernel/lib/bitset.c b/src/kernel/lib/bitset.c deleted file mode 100644 index a6d334b..0000000 --- a/src/kernel/lib/bitset.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "bitset.h" - -void bitset_set(struct bitset* t, uint32_t num) { - uint32_t idx = INDEX_FROM_BIT(num); - uint32_t off = OFFSET_FROM_BIT(num); - t->bits[idx] |= (0x1 << off); -} - -void bitset_clear(struct bitset* t, uint32_t num) { - uint32_t idx = INDEX_FROM_BIT(num); - uint32_t off = OFFSET_FROM_BIT(num); - t->bits[idx] &= ~(0x1 << off); -} - -uint32_t bitset_test(struct bitset* t, uint32_t num) { - uint32_t idx = INDEX_FROM_BIT(num); - uint32_t off = OFFSET_FROM_BIT(num); - return (t->bits[idx] & (0x1 << off)); -} - -uint32_t bitset_firstFree(struct bitset* t) { - uint32_t i, j; - for (i = 0; i < INDEX_FROM_BIT(t->size); i++) { - if (t->bits[i] != 0xFFFFFFFF) { - for (j = 0; j < 32; j++) { - uint32_t toTest = 0x1 << j; - if (!(t->bits[i] & toTest)) { - return i*4*8+j; - } - } - } - } - return (uint32_t) - 1; -} - diff --git a/src/kernel/lib/bitset.cpp b/src/kernel/lib/bitset.cpp new file mode 100644 index 0000000..2b3d2e9 --- /dev/null +++ b/src/kernel/lib/bitset.cpp @@ -0,0 +1,35 @@ +#include "bitset.h" + +void bitset::set(uint32_t num) { + uint32_t idx = INDEX_FROM_BIT(num); + uint32_t off = OFFSET_FROM_BIT(num); + bits[idx] |= (0x1 << off); +} + +void bitset::clear(uint32_t num) { + uint32_t idx = INDEX_FROM_BIT(num); + uint32_t off = OFFSET_FROM_BIT(num); + bits[idx] &= ~(0x1 << off); +} + +uint32_t bitset::test(uint32_t num) { + uint32_t idx = INDEX_FROM_BIT(num); + uint32_t off = OFFSET_FROM_BIT(num); + return (bits[idx] & (0x1 << off)); +} + +uint32_t bitset::firstFree() { + uint32_t i, j; + for (i = 0; i < INDEX_FROM_BIT(size); i++) { + if (bits[i] != 0xFFFFFFFF) { + for (j = 0; j < 32; j++) { + uint32_t toTest = 0x1 << j; + if (!(bits[i] & toTest)) { + return i*4*8+j; + } + } + } + } + return (uint32_t) - 1; +} + diff --git a/src/kernel/lib/bitset.h b/src/kernel/lib/bitset.h index fe9e8c2..f2441ce 100644 --- a/src/kernel/lib/bitset.h +++ b/src/kernel/lib/bitset.h @@ -9,11 +9,12 @@ struct bitset { uint32_t *bits; uint32_t size; + + void set(uint32_t num); + void clear(uint32_t num); + uint32_t test(uint32_t num); + uint32_t firstFree(); }; -void bitset_set(struct bitset* t, uint32_t num); -void bitset_clear(struct bitset* t, uint32_t num); -uint32_t bitset_test(struct bitset* t, uint32_t num); -uint32_t bitset_firstFree(struct bitset* t); #endif diff --git a/src/kernel/lib/cpp.h b/src/kernel/lib/cpp.h new file mode 100644 index 0000000..cf08ede --- /dev/null +++ b/src/kernel/lib/cpp.h @@ -0,0 +1,16 @@ +#ifndef DEF_CPPSUPPORT_H +#define DEF_CPPSUPPORT_H + +#include + +inline void* operator new(size_t, void* p) throw() { return p; } +inline void* operator new[](size_t, void* p) throw() { return p; } +inline void operator delete (void*, void*) throw() { }; +inline void operator delete[](void*, void*) throw() { }; + +inline void* operator new (size_t size) { return kmalloc(size); } +inline void* operator new[] (size_t size) { return kmalloc(size); } +inline void operator delete (void* ptr) { return kfree(ptr); } +inline void operator delete[] (void* ptr) { return kfree(ptr); } + +#endif diff --git a/src/kernel/lib/std.c b/src/kernel/lib/std.c deleted file mode 100644 index 316dfa3..0000000 --- a/src/kernel/lib/std.c +++ /dev/null @@ -1,11 +0,0 @@ -#include "std.h" -#include "core/sys.h" - -int errno = 0; - -void abort() { - monitor_write("\n\n ABORT - errno: "); - monitor_writeDec(errno); - monitor_write("\n"); - PANIC("abort() called, probably a memory manager failure."); -} diff --git a/src/kernel/lib/std.cpp b/src/kernel/lib/std.cpp new file mode 100644 index 0000000..7ab4f64 --- /dev/null +++ b/src/kernel/lib/std.cpp @@ -0,0 +1,12 @@ +#include "std.h" +#include "core/sys.h" +#include "core/monitor.h" + +int errno = 0; + +void abort() { + monitor_write("\n\n ABORT - errno: "); + monitor_writeDec(errno); + monitor_write("\n"); + PANIC("abort() called, probably a memory manager failure."); +} diff --git a/src/kernel/lib/std.h b/src/kernel/lib/std.h index 51e0435..ced49b5 100644 --- a/src/kernel/lib/std.h +++ b/src/kernel/lib/std.h @@ -5,7 +5,12 @@ #include /* For size_t */ +#ifdef __cplusplus +extern "C" void abort(); +#else void abort(); +#endif + #define sbrk ksbrk #define brk kbrk diff --git a/src/kernel/linker/elf.c b/src/kernel/linker/elf.c deleted file mode 100644 index af6d057..0000000 --- a/src/kernel/linker/elf.c +++ /dev/null @@ -1,57 +0,0 @@ -#include "elf.h" -#include -#include -#include -#include - -int elf_check(uint8_t *data) { - struct elf_ehdr *h = (struct elf_ehdr*)data; - if (h->e_ident[0] == 0x7F && h->e_ident[1] == 'E' && h->e_ident[2] == 'L' && h->e_ident[3] == 'F') return 0; - return 1; -} - -thread_entry elf_load(uint8_t *data, struct process* process) { - struct elf_ehdr *ehdr = (struct elf_ehdr*)data; - struct elf_phdr *phdr; - int i; - size_t dataseg = 0; - if (elf_check(data)) return 0; - - struct page_directory *r = current_pagedir; - cli(); - pagedir_switch(process->pagedir); - - phdr = (struct elf_phdr*)((uint8_t*)(data + ehdr->e_phoff)); - for (i = 0; i < ehdr->e_phnum; i++) { - if (phdr[i].p_type == PT_LOAD) { - seg_map(simpleseg_make(phdr[i].p_vaddr, phdr[i].p_memsz, (phdr[i].p_flags & PF_W) != 0), process->pagedir, 0); - memcpy((uint8_t*)phdr[i].p_vaddr, data + phdr[i].p_offset, phdr[i].p_filesz); - if (phdr[i].p_memsz > phdr[i].p_filesz) { - memset((uint8_t*)phdr[i].p_vaddr + phdr[i].p_memsz, 0, phdr[i].p_memsz - phdr[i].p_filesz); - } - if (phdr[i].p_vaddr + phdr[i].p_memsz > dataseg) { - dataseg = phdr[i].p_vaddr + phdr[i].p_memsz; - dataseg = (dataseg & 0xFFFFF000) + 0x1000; - } - } - } - - process->data = dataseg; - - pagedir_switch(r); - sti(); - - return (thread_entry)ehdr->e_entry; -} - -struct process* elf_exec(uint8_t *data, int privilege) { - if (elf_check(data)) return 0; - - struct process* p = process_new(0, 0, privilege); - - thread_entry e = elf_load(data, p); - - thread_new(p, e, 0, 0); - - return p; -} diff --git a/src/kernel/linker/elf.cpp b/src/kernel/linker/elf.cpp new file mode 100644 index 0000000..ab8e349 --- /dev/null +++ b/src/kernel/linker/elf.cpp @@ -0,0 +1,57 @@ +#include "elf.h" +#include +#include +#include +#include + +int elf_check(uint8_t *data) { + elf_ehdr *h = (elf_ehdr*)data; + if (h->e_ident[0] == 0x7F && h->e_ident[1] == 'E' && h->e_ident[2] == 'L' && h->e_ident[3] == 'F') return 0; + return 1; +} + +thread_entry elf_load(uint8_t *data, process* process) { + elf_ehdr *ehdr = (elf_ehdr*)data; + elf_phdr *phdr; + int i; + size_t dataseg = 0; + if (elf_check(data)) return 0; + + page_directory *r = current_pagedir; + cli(); + pagedir_switch(process->pagedir); + + phdr = (elf_phdr*)((uint8_t*)(data + ehdr->e_phoff)); + for (i = 0; i < ehdr->e_phnum; i++) { + if (phdr[i].p_type == PT_LOAD) { + seg_map(simpleseg_make(phdr[i].p_vaddr, phdr[i].p_memsz, (phdr[i].p_flags & PF_W) != 0), process->pagedir, 0); + memcpy((uint8_t*)phdr[i].p_vaddr, data + phdr[i].p_offset, phdr[i].p_filesz); + if (phdr[i].p_memsz > phdr[i].p_filesz) { + memset((uint8_t*)phdr[i].p_vaddr + phdr[i].p_memsz, 0, phdr[i].p_memsz - phdr[i].p_filesz); + } + if (phdr[i].p_vaddr + phdr[i].p_memsz > dataseg) { + dataseg = phdr[i].p_vaddr + phdr[i].p_memsz; + dataseg = (dataseg & 0xFFFFF000) + 0x1000; + } + } + } + + process->data = dataseg; + + pagedir_switch(r); + sti(); + + return (thread_entry)ehdr->e_entry; +} + +process* elf_exec(uint8_t *data, int privilege) { + if (elf_check(data)) return 0; + + process* p = process_new(0, 0, privilege); + + thread_entry e = elf_load(data, p); + + thread_new(p, e, 0, 0); + + return p; +} diff --git a/src/kernel/linker/elf.h b/src/kernel/linker/elf.h index c32cce0..bb61795 100644 --- a/src/kernel/linker/elf.h +++ b/src/kernel/linker/elf.h @@ -52,12 +52,12 @@ struct elf_phdr { }; struct phdr { - struct elf_phdr h; + elf_phdr h; uint8_t* data; }; int elf_check(uint8_t *data); //0 if ok, 1 if not a valid ELF -thread_entry elf_load(uint8_t *data, struct process* process); //Load an ELF to a process, return entry point -struct process* elf_exec(uint8_t *data, int privilege); //Creates a new process and a thread for running ELF file +thread_entry elf_load(uint8_t *data, process* process); //Load an ELF to a process, return entry point +process* elf_exec(uint8_t *data, int privilege); //Creates a new process and a thread for running ELF file #endif diff --git a/src/kernel/mem/_dlmalloc.h b/src/kernel/mem/_dlmalloc.h index 7b2e2cc..a80273c 100644 --- a/src/kernel/mem/_dlmalloc.h +++ b/src/kernel/mem/_dlmalloc.h @@ -1,6 +1,7 @@ #ifndef DEF_DLMALLOC_H #define DEF_DLMALLOC_H +#include #include "lib/std.h" #include #include @@ -16,6 +17,8 @@ #define USE_LOCKS 2 + + /* Version identifier to allow people to support multiple versions */ #ifndef DLMALLOC_VERSION #define DLMALLOC_VERSION 20805 diff --git a/src/kernel/mem/gdt.c b/src/kernel/mem/gdt.c deleted file mode 100644 index 494aaf2..0000000 --- a/src/kernel/mem/gdt.c +++ /dev/null @@ -1,64 +0,0 @@ -#include "gdt.h" -#include -#include - -extern void gdt_flush(uint32_t); //ASM (imported from idt_.asm) -extern void tss_flush(); - -#define GDT_ENTRIES 6 // The contents of each entry is defined in gdt_init. - -static struct tss_entry tss_entry; -static struct gdt_entry gdt_entries[GDT_ENTRIES]; -static struct gdt_ptr gdt_ptr; - -/* This function is called by the task_switch function on each context switch. - It updates the TSS so that an interrupt will be handled on the correct kernel stack - (one kernel stack is allocated to each thread). */ -void gdt_setKernelStack(uint32_t esp0) { - tss_entry.esp0 = esp0; -} - -/* For internal use only. Writes one entry of the GDT with given parameters. */ -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; -} - -/* For internal use only. Writes one entry of the GDT, that entry being a pointer to the TSS. */ -static void gdt_writeTss(int num, uint32_t ss0, uint32_t esp0) { - uint32_t base = (uint32_t)&tss_entry; - uint32_t limit = base + sizeof(struct tss_entry); - - gdt_setGate(num, base, limit, 0xE9, 0); - - memset(&tss_entry, 0, sizeof(struct tss_entry)); - - tss_entry.ss0 = ss0; tss_entry.esp0 = esp0; - - tss_entry.cs = 0x0b; - tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; -} - -/* Write data to the GDT and enable it. */ -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 0x08 - gdt_setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment 0x10 - gdt_setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment 0x18 - gdt_setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20 - gdt_writeTss(5, 0x10, 0); - - gdt_flush((uint32_t)&gdt_ptr); - tss_flush(); - - monitor_write("[GDT] "); -} diff --git a/src/kernel/mem/gdt.cpp b/src/kernel/mem/gdt.cpp new file mode 100644 index 0000000..49fbd82 --- /dev/null +++ b/src/kernel/mem/gdt.cpp @@ -0,0 +1,64 @@ +#include "gdt.h" +#include +#include + +extern "C" void gdt_flush(uint32_t); //ASM (imported from idt_.asm) +extern "C" void tss_flush(); + +#define GDT_ENTRIES 6 // The contents of each entry is defined in gdt_init. + +static tss_entry tss_entry; +static gdt_entry gdt_entries[GDT_ENTRIES]; +static gdt_ptr gdt_ptr; + +/* This function is called by the task_switch function on each context switch. + It updates the TSS so that an interrupt will be handled on the correct kernel stack + (one kernel stack is allocated to each thread). */ +void gdt_setKernelStack(uint32_t esp0) { + tss_entry.esp0 = esp0; +} + +/* For internal use only. Writes one entry of the GDT with given parameters. */ +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; +} + +/* For internal use only. Writes one entry of the GDT, that entry being a pointer to the TSS. */ +static void gdt_writeTss(int num, uint32_t ss0, uint32_t esp0) { + uint32_t base = (uint32_t)&tss_entry; + uint32_t limit = base + sizeof(tss_entry); + + gdt_setGate(num, base, limit, 0xE9, 0); + + memset(&tss_entry, 0, sizeof(tss_entry)); + + tss_entry.ss0 = ss0; tss_entry.esp0 = esp0; + + tss_entry.cs = 0x0b; + tss_entry.ss = tss_entry.ds = tss_entry.es = tss_entry.fs = tss_entry.gs = 0x13; +} + +/* Write data to the GDT and enable it. */ +void gdt_init() { + gdt_ptr.limit = (sizeof(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 0x08 + gdt_setGate(2, 0, 0xFFFFFFFF, 0x92, 0xCF); //Kernel data segment 0x10 + gdt_setGate(3, 0, 0xFFFFFFFF, 0xFA, 0xCF); //User code segment 0x18 + gdt_setGate(4, 0, 0xFFFFFFFF, 0xF2, 0xCF); //User data segment 0x20 + gdt_writeTss(5, 0x10, 0); + + gdt_flush((uint32_t)&gdt_ptr); + tss_flush(); + + monitor_write("[GDT] "); +} diff --git a/src/kernel/mem/mem.c b/src/kernel/mem/mem.c deleted file mode 100644 index 3310b70..0000000 --- a/src/kernel/mem/mem.c +++ /dev/null @@ -1,137 +0,0 @@ -#include "mem.h" -#include -#include -#include "paging.h" - -#include - -#include "_dlmalloc.h" - -#include "mem.h" - -#define FREEPAGESTOKEEP 5 - -#define KHEAP_IDXSIZE 0x4000 // only used with heap.std.h -#define KHEAP_INITSIZE 0x00080000 -#define KHEAP_MAXSIZE 0x08000000 - -size_t mem_placementAddr; -int _no_more_ksbrk = 0; - - -// ****************************** -// PAGE ALLOCATION -// **************************** -static struct freepage { - size_t virt, phys; -} freepages[FREEPAGESTOKEEP]; -uint32_t freepagecount = 0; - -/* For internal use only. Populates the cache of pages that can be given to requesters. */ -static void get_free_pages() { - static uint32_t locked = 0; - uint32_t i; - if (locked) return; - locked = 1; - while (freepagecount < FREEPAGESTOKEEP) { - if (_no_more_ksbrk) { - for (i = 0xFFFFF000; i >= 0xF0000000; i -= 0x1000) { - if (pagedir_getPage(kernel_pagedir, i, 1)->frame == 0) break; - } - freepages[freepagecount].virt = i; - uint32_t frame = frame_alloc(); - freepages[freepagecount].phys = frame * 0x1000; - page_map(pagedir_getPage(kernel_pagedir, i, 0), freepages[freepagecount].phys / 0x1000, 0, 0); - freepagecount++; - } else { - if (mem_placementAddr & 0xFFFFF000) { - mem_placementAddr &= 0xFFFFF000; - mem_placementAddr += 0x1000; - } - freepages[freepagecount].virt = (size_t)ksbrk(0x1000); - freepages[freepagecount].phys = freepages[freepagecount].virt - K_HIGHHALF_ADDR; - freepagecount++; - } - } - locked = 0; -} - -/* Gives one page from the cache to someone requesting it. */ -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 (_no_more_ksbrk) { - page_unmapFree(pagedir_getPage(kernel_pagedir, addr, 0)); - } -} - -//*********************************** -// MEMORY ALLOCATION FOR DLMALLOC -// ************************* - -void* ksbrk(size_t size) { - if (_no_more_ksbrk == 0) { // ksbrk is NOT being called by dlmalloc - if (size & 0x0FFF) { - size = (size & 0xFFFFF000) + 0x1000; - } - } - - size_t tmp = mem_placementAddr; - size_t er_begin, er_end, i; - - /* (DBG) monitor_write(" "); */ - - mem_placementAddr += size; - - if (_no_more_ksbrk) { // paging enabled, we must allocate these pages - if (tmp < mem_placementAddr) { - er_begin = tmp; - if (er_begin & 0x0FFF) er_begin = (er_begin & 0xFFFFF000) + 0x1000; - er_end = mem_placementAddr; - if (er_end & 0x0FFF) er_end = (er_end & 0xFFFFF000) + 0x1000; - for (i = er_begin; i < er_end; i += 0x1000) { - struct page *p = pagedir_getPage(kernel_pagedir, i, 1); - size_t f = frame_alloc(); - page_map(p, f, 0, 0); - /* (DBG) monitor_write(" "); */ - } - } else if (tmp > mem_placementAddr) { - er_begin = (size_t)mem_placementAddr; - if (er_begin & 0x0FFF) er_begin = (er_begin & 0xFFFFF000) + 0x1000; - er_end = tmp; - if (er_end & 0x0FFF) er_end = (er_end & 0xFFFFF000) + 0x1000; - for (i = er_end - 0x1000; i >= er_begin; i -= 0x1000) { - // (DBG) monitor_write(" "); - page_unmapFree(pagedir_getPage(kernel_pagedir, i, 0)); - } - } - } - - return (void*)tmp; -} - -void kbrk(void* ptr) { - monitor_write("\n"); - - if ((size_t)ptr > (size_t)&end) { - ksbrk(ptr - (size_t)mem_placementAddr); - } else { - PANIC("INVALID KBRK."); - } -} diff --git a/src/kernel/mem/mem.cpp b/src/kernel/mem/mem.cpp new file mode 100644 index 0000000..5e04de3 --- /dev/null +++ b/src/kernel/mem/mem.cpp @@ -0,0 +1,137 @@ +#include "mem.h" +#include +#include +#include "paging.h" + +#include + +#include "_dlmalloc.h" + +#include "mem.h" + +#define FREEPAGESTOKEEP 5 + +#define KHEAP_IDXSIZE 0x4000 // only used with heap.std.h +#define KHEAP_INITSIZE 0x00080000 +#define KHEAP_MAXSIZE 0x08000000 + +size_t mem_placementAddr; +bool _no_more_ksbrk = false; + + +// ****************************** +// PAGE ALLOCATION +// **************************** +static struct freepage { + size_t virt, phys; +} freepages[FREEPAGESTOKEEP]; +uint32_t freepagecount = 0; + +/* For internal use only. Populates the cache of pages that can be given to requesters. */ +static void get_free_pages() { + static uint32_t locked = 0; + uint32_t i; + if (locked) return; + locked = 1; + while (freepagecount < FREEPAGESTOKEEP) { + if (_no_more_ksbrk) { + for (i = 0xFFFFF000; i >= 0xF0000000; i -= 0x1000) { + if (pagedir_getPage(kernel_pagedir, i, 1)->frame == 0) break; + } + freepages[freepagecount].virt = i; + uint32_t frame = frame_alloc(); + freepages[freepagecount].phys = frame * 0x1000; + page_map(pagedir_getPage(kernel_pagedir, i, 0), freepages[freepagecount].phys / 0x1000, 0, 0); + freepagecount++; + } else { + if (mem_placementAddr & 0xFFFFF000) { + mem_placementAddr &= 0xFFFFF000; + mem_placementAddr += 0x1000; + } + freepages[freepagecount].virt = (size_t)ksbrk(0x1000); + freepages[freepagecount].phys = freepages[freepagecount].virt - K_HIGHHALF_ADDR; + freepagecount++; + } + } + locked = 0; +} + +/* Gives one page from the cache to someone requesting it. */ +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 (_no_more_ksbrk) { + page_unmapFree(pagedir_getPage(kernel_pagedir, addr, 0)); + } +} + +//*********************************** +// MEMORY ALLOCATION FOR DLMALLOC +// ************************* + +void* ksbrk(size_t size) { + if (!_no_more_ksbrk) { // ksbrk is NOT being called by dlmalloc + if (size & 0x0FFF) { + size = (size & 0xFFFFF000) + 0x1000; + } + } + + size_t tmp = mem_placementAddr; + size_t er_begin, er_end, i; + + /* (DBG) monitor_write(" "); */ + + mem_placementAddr += size; + + if (_no_more_ksbrk) { // paging enabled, we must allocate these pages + if (tmp < mem_placementAddr) { + er_begin = tmp; + if (er_begin & 0x0FFF) er_begin = (er_begin & 0xFFFFF000) + 0x1000; + er_end = mem_placementAddr; + if (er_end & 0x0FFF) er_end = (er_end & 0xFFFFF000) + 0x1000; + for (i = er_begin; i < er_end; i += 0x1000) { + page *p = pagedir_getPage(kernel_pagedir, i, 1); + size_t f = frame_alloc(); + page_map(p, f, 0, 0); + /* (DBG) monitor_write(" "); */ + } + } else if (tmp > mem_placementAddr) { + er_begin = (size_t)mem_placementAddr; + if (er_begin & 0x0FFF) er_begin = (er_begin & 0xFFFFF000) + 0x1000; + er_end = tmp; + if (er_end & 0x0FFF) er_end = (er_end & 0xFFFFF000) + 0x1000; + for (i = er_end - 0x1000; i >= er_begin; i -= 0x1000) { + // (DBG) monitor_write(" "); + page_unmapFree(pagedir_getPage(kernel_pagedir, i, 0)); + } + } + } + + return (void*)tmp; +} + +void kbrk(void* ptr) { + monitor_write("\n"); + + if ((size_t)ptr > (size_t)&end) { + ksbrk((size_t)ptr - (size_t)mem_placementAddr); + } else { + PANIC("INVALID KBRK."); + } +} diff --git a/src/kernel/mem/mem.h b/src/kernel/mem/mem.h index cb9c396..085d9ce 100644 --- a/src/kernel/mem/mem.h +++ b/src/kernel/mem/mem.h @@ -11,19 +11,17 @@ void* kmalloc_page(size_t *phys); void kfree_page(void* page); // Internal, used by dlmalloc -void* ksbrk(size_t size); -void kbrk(void* ptr); +extern "C" void* ksbrk(size_t size); +extern "C" void kbrk(void* ptr); #define kmalloc dlmalloc #define kfree dlfree -void kheap_init(); - -extern int _no_more_ksbrk; +extern bool _no_more_ksbrk; extern size_t mem_placementAddr; -extern void end; //Symbol defined by linker : end of kernel code +extern "C" size_t end; //Symbol defined by linker : end of kernel code -extern void k_highhalf_addr; // Symbol defined by linker : high half position of the kerne +extern "C" size_t k_highhalf_addr; // Symbol defined by linker : high half position of the kerne // Should be at 0xC0000000 #define K_HIGHHALF_ADDR ((size_t)(&k_highhalf_addr)) diff --git a/src/kernel/mem/paging.c b/src/kernel/mem/paging.c deleted file mode 100644 index 0527f06..0000000 --- a/src/kernel/mem/paging.c +++ /dev/null @@ -1,203 +0,0 @@ -#include "paging.h" -#include -#include -#include -#include "mem.h" -#include "seg.h" -#include -#include - -static struct bitset frames; - -struct page_directory *kernel_pagedir, *current_pagedir; - -/************************** PHYSICAL MEMORY ALLOCATION ************************/ - -/* Allocates a page of physical memory. */ -uint32_t frame_alloc() { - uint32_t free = bitset_firstFree(&frames); - if (free == (uint32_t) -1) { - PANIC("No more frames to allocate, system is out of memory!"); - } - bitset_set(&frames, free); - return free; -} - -void frame_free(uint32_t id) { - bitset_clear(&frames, id); -} - -/************************* PAGING INITIALIZATION *****************************/ - -/* This function creates the kernel page directory. It must be called before the GDT is loaded. - It maps 0xC0000000+ (k_highhalf_addr) to the corresponding physical kernel code, but it also maps - 0x00000000+ to that code because with the false GDT we set up in loader_.asm, - the code will be looked for at the beginning of the memory. Only when the real GDT is loaded - we can de-allocate pages at 0x00000000 ; this is done by paging_cleanup. */ -void paging_init(size_t totalRam) { - uint32_t i; - - frames.size = totalRam / 0x1000; - frames.bits = ksbrk(INDEX_FROM_BIT(frames.size)); - - kernel_pagedir = ksbrk(sizeof(struct page_directory)); - kernel_pagedir->mappedSegs = 0; - kernel_pagedir->tablesPhysical = kmalloc_page(&kernel_pagedir->physicalAddr); - for (i = 0; i < 1024; i++) { - kernel_pagedir->tables[i] = 0; - kernel_pagedir->tablesPhysical[i] = 0; - } - - for (i = K_HIGHHALF_ADDR; i < mem_placementAddr; i += 0x1000) { - page_map(pagedir_getPage(kernel_pagedir, i, 1), frame_alloc(), 0, 0); - } - for (i = 0; i < (mem_placementAddr - K_HIGHHALF_ADDR) / 0x100000; i++) { - kernel_pagedir->tablesPhysical[i] = kernel_pagedir->tablesPhysical[i + FIRST_KERNEL_PAGETABLE]; - kernel_pagedir->tables[i] = kernel_pagedir->tables[i + FIRST_KERNEL_PAGETABLE]; - } - - monitor_write("{PD: "); - monitor_writeHex(kernel_pagedir->physicalAddr); - pagedir_switch(kernel_pagedir); - monitor_write("} [Paging] "); -} - -/* De-allocates pages at 0x00000000 where kernel code was read from with the GDT from loader_.asm. */ -void paging_cleanup() { - size_t i; - for (i = 0; i < (mem_placementAddr - K_HIGHHALF_ADDR) / 0x100000; i++) { - kernel_pagedir->tablesPhysical[i] = 0; - kernel_pagedir->tables[i] = 0; - } - monitor_write("[PD Cleanup] "); -} - -/************************* PAGING EVERYDAY USE *****************************/ - -/* Switch to a page directory. Can be done if we are sure not to be interrupted by a task switch. - Example use for cross-memory space writing in linker/elf.c */ -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)); -} - -/* Creates a new page directory for a process, and maps the kernel page tables on it. */ -struct page_directory *pagedir_new() { - uint32_t i; - - struct page_directory *pd = kmalloc(sizeof(struct page_directory)); - pd->tablesPhysical = kmalloc_page(&pd->physicalAddr); - pd->mappedSegs = 0; - - for (i = 0; i < 1024; i++) { - pd->tables[i] = 0; pd->tablesPhysical[i] = 0; - } - - for (i = FIRST_KERNEL_PAGETABLE; i < 1024; i++) { - pd->tables[i] = kernel_pagedir->tables[i]; - pd->tablesPhysical[i] = kernel_pagedir->tablesPhysical[i]; - } - - return pd; -} - -/* Deletes a page directory, cleaning it up. */ -void pagedir_delete(struct page_directory *pd) { - uint32_t i; - //Unmap segments - while (pd->mappedSegs != 0) seg_unmap(pd->mappedSegs); - //Cleanup page tables - for (i = 0; i < FIRST_KERNEL_PAGETABLE; i++) { - kfree_page(pd->tables[i]); - } - kfree_page(pd->tablesPhysical); - kfree(pd); -} - -/* Handle a paging fault. First, looks for the corresponding segment. - If the segment was found and it handles the fault, return normally. - Else, display informatinos and return an error. */ -uint32_t paging_fault(struct registers *regs) { - size_t addr; - struct segment_map *seg = 0; - asm volatile("mov %%cr2, %0" : "=r"(addr)); - - seg = current_pagedir->mappedSegs; - while (seg) { - if (seg->start <= addr && seg->start + seg->len > addr) break; - seg = seg->next; - } - - if (seg != 0) { - if (seg->seg->handle_fault(seg, addr, (regs->err_code & 0x2) && (regs->eip < K_HIGHHALF_ADDR)) != 0) seg = 0; - } - - if (seg == 0) { - NL; WHERE; monitor_write("Unhandled Page Fault\t"); - monitor_write("cr2:"); monitor_writeHex(addr); - NL; TAB; - if (regs->err_code & 0x1) monitor_write("present"); TAB; - if (regs->err_code & 0x2) monitor_write("write"); TAB; - if (regs->err_code & 0x4) monitor_write("user"); TAB; - if (regs->err_code & 0x8) monitor_write("rsvd"); TAB; - if (regs->err_code & 0x10) monitor_write("opfetch"); - return 1; - } - return 0; -} - -/* Gets the corresponding page in a page directory for a given address. - If make is set, the necessary page table can be created. - Can return 0 if make is not set. */ -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; - - if (table_idx >= FIRST_KERNEL_PAGETABLE) { - tasking_updateKernelPagetable(table_idx, pd->tables[table_idx], pd->tablesPhysical[table_idx]); - } - - return &pd->tables[table_idx]->pages[address % 1024]; - } else { - return 0; - } -} - -/* Modifies a page structure so that it is mapped to a frame. */ -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; - } -} - -/* Modifies a page structure so that it is no longer mapped to a frame. */ -void page_unmap(struct page *page) { - if (page != 0) { - page->frame = 0; - page->present = 0; - } -} - -/* Same as above but also frees the frame. */ -void page_unmapFree(struct page *page) { - if (page != 0) { - if (page->frame != 0) frame_free(page->frame); - page->frame = 0; - page->present = 0; - } -} diff --git a/src/kernel/mem/paging.cpp b/src/kernel/mem/paging.cpp new file mode 100644 index 0000000..eb7e615 --- /dev/null +++ b/src/kernel/mem/paging.cpp @@ -0,0 +1,203 @@ +#include "paging.h" +#include +#include +#include +#include "mem.h" +#include "seg.h" +#include +#include + +static bitset frames; + +page_directory *kernel_pagedir, *current_pagedir; + +/************************** PHYSICAL MEMORY ALLOCATION ************************/ + +/* Allocates a page of physical memory. */ +uint32_t frame_alloc() { + uint32_t free = frames.firstFree(); + if (free == (uint32_t) -1) { + PANIC("No more frames to allocate, system is out of memory!"); + } + frames.set(free); + return free; +} + +void frame_free(uint32_t id) { + frames.clear(id); +} + +/************************* PAGING INITIALIZATION *****************************/ + +/* This function creates the kernel page directory. It must be called before the GDT is loaded. + It maps 0xC0000000+ (k_highhalf_addr) to the corresponding physical kernel code, but it also maps + 0x00000000+ to that code because with the false GDT we set up in loader_.asm, + the code will be looked for at the beginning of the memory. Only when the real GDT is loaded + we can de-allocate pages at 0x00000000 ; this is done by paging_cleanup. */ +void paging_init(size_t totalRam) { + uint32_t i; + + frames.size = totalRam / 0x1000; + frames.bits = (uint32_t*)ksbrk(INDEX_FROM_BIT(frames.size)); + + kernel_pagedir = (page_directory*)ksbrk(sizeof(page_directory)); + kernel_pagedir->mappedSegs = 0; + kernel_pagedir->tablesPhysical = (uint32_t*)kmalloc_page(&kernel_pagedir->physicalAddr); + for (i = 0; i < 1024; i++) { + kernel_pagedir->tables[i] = 0; + kernel_pagedir->tablesPhysical[i] = 0; + } + + for (i = K_HIGHHALF_ADDR; i < mem_placementAddr; i += 0x1000) { + page_map(pagedir_getPage(kernel_pagedir, i, 1), frame_alloc(), 0, 0); + } + for (i = 0; i < (mem_placementAddr - K_HIGHHALF_ADDR) / 0x100000; i++) { + kernel_pagedir->tablesPhysical[i] = kernel_pagedir->tablesPhysical[i + FIRST_KERNEL_PAGETABLE]; + kernel_pagedir->tables[i] = kernel_pagedir->tables[i + FIRST_KERNEL_PAGETABLE]; + } + + monitor_write("{PD: "); + monitor_writeHex(kernel_pagedir->physicalAddr); + pagedir_switch(kernel_pagedir); + monitor_write("} [Paging] "); +} + +/* De-allocates pages at 0x00000000 where kernel code was read from with the GDT from loader_.asm. */ +void paging_cleanup() { + size_t i; + for (i = 0; i < (mem_placementAddr - K_HIGHHALF_ADDR) / 0x100000; i++) { + kernel_pagedir->tablesPhysical[i] = 0; + kernel_pagedir->tables[i] = 0; + } + monitor_write("[PD Cleanup] "); +} + +/************************* PAGING EVERYDAY USE *****************************/ + +/* Switch to a page directory. Can be done if we are sure not to be interrupted by a task switch. + Example use for cross-memory space writing in linker/elf.c */ +void pagedir_switch(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)); +} + +/* Creates a new page directory for a process, and maps the kernel page tables on it. */ +page_directory *pagedir_new() { + uint32_t i; + + page_directory *pd = new page_directory(); + pd->tablesPhysical = (uint32_t*)kmalloc_page(&pd->physicalAddr); + pd->mappedSegs = 0; + + for (i = 0; i < 1024; i++) { + pd->tables[i] = 0; pd->tablesPhysical[i] = 0; + } + + for (i = FIRST_KERNEL_PAGETABLE; i < 1024; i++) { + pd->tables[i] = kernel_pagedir->tables[i]; + pd->tablesPhysical[i] = kernel_pagedir->tablesPhysical[i]; + } + + return pd; +} + +/* Deletes a page directory, cleaning it up. */ +void pagedir_delete(page_directory *pd) { + uint32_t i; + //Unmap segments + while (pd->mappedSegs != 0) seg_unmap(pd->mappedSegs); + //Cleanup page tables + for (i = 0; i < FIRST_KERNEL_PAGETABLE; i++) { + kfree_page(pd->tables[i]); + } + kfree_page(pd->tablesPhysical); + kfree(pd); +} + +/* Handle a paging fault. First, looks for the corresponding segment. + If the segment was found and it handles the fault, return normally. + Else, display informatinos and return an error. */ +uint32_t paging_fault(registers *regs) { + size_t addr; + segment_map *seg = 0; + asm volatile("mov %%cr2, %0" : "=r"(addr)); + + seg = current_pagedir->mappedSegs; + while (seg) { + if (seg->start <= addr && seg->start + seg->len > addr) break; + seg = seg->next; + } + + if (seg != 0) { + if (seg->seg->handle_fault(seg, addr, (regs->err_code & 0x2) && (regs->eip < K_HIGHHALF_ADDR)) != 0) seg = 0; + } + + if (seg == 0) { + NL; WHERE; monitor_write("Unhandled Page Fault\t"); + monitor_write("cr2:"); monitor_writeHex(addr); + NL; TAB; + if (regs->err_code & 0x1) monitor_write("present"); TAB; + if (regs->err_code & 0x2) monitor_write("write"); TAB; + if (regs->err_code & 0x4) monitor_write("user"); TAB; + if (regs->err_code & 0x8) monitor_write("rsvd"); TAB; + if (regs->err_code & 0x10) monitor_write("opfetch"); + return 1; + } + return 0; +} + +/* Gets the corresponding page in a page directory for a given address. + If make is set, the necessary page table can be created. + Can return 0 if make is not set. */ +page *pagedir_getPage(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] = (page_table*)kmalloc_page(pd->tablesPhysical + table_idx); + + memset((uint8_t*)pd->tables[table_idx], 0, 0x1000); + pd->tablesPhysical[table_idx] |= 0x07; + + if (table_idx >= FIRST_KERNEL_PAGETABLE) { + tasking_updateKernelPagetable(table_idx, pd->tables[table_idx], pd->tablesPhysical[table_idx]); + } + + return &pd->tables[table_idx]->pages[address % 1024]; + } else { + return 0; + } +} + +/* Modifies a page structure so that it is mapped to a frame. */ +void page_map(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; + } +} + +/* Modifies a page structure so that it is no longer mapped to a frame. */ +void page_unmap(page *page) { + if (page != 0) { + page->frame = 0; + page->present = 0; + } +} + +/* Same as above but also frees the frame. */ +void page_unmapFree(page *page) { + if (page != 0) { + if (page->frame != 0) frame_free(page->frame); + page->frame = 0; + page->present = 0; + } +} diff --git a/src/kernel/mem/paging.h b/src/kernel/mem/paging.h index 2d5713f..f91fe37 100644 --- a/src/kernel/mem/paging.h +++ b/src/kernel/mem/paging.h @@ -18,32 +18,32 @@ struct page { }; struct page_table { - struct page pages[1024]; + page pages[1024]; }; struct segment_map; struct page_directory { - struct page_table *tables[1024]; //Virtual addresses of page tables + page_table *tables[1024]; //Virtual addresses of page tables uint32_t *tablesPhysical; //Pointer to the virtual address of the page directory (contain phys addr of pt) uint32_t physicalAddr; //Physical address of info above - struct segment_map *mappedSegs; + segment_map *mappedSegs; }; -extern struct page_directory *kernel_pagedir, *current_pagedir; +extern page_directory *kernel_pagedir, *current_pagedir; uint32_t frame_alloc(); void frame_free(uint32_t id); void paging_init(size_t totalRam); void paging_cleanup(); -void pagedir_switch(struct page_directory *pd); -struct page_directory *pagedir_new(); //Creates a brand new empty page directory for a process, with kernel pages -void pagedir_delete(struct page_directory *pagedir); -struct page *pagedir_getPage(struct page_directory *pd, uint32_t address, int make); -void page_map(struct page *page, uint32_t frame, uint32_t user, uint32_t rw); -void page_unmap(struct page *page); -void page_unmapFree(struct page *page); - -uint32_t paging_fault(struct registers *regs); //returns a boolean : 1 if unhandled, 0 if ok +void pagedir_switch(page_directory *pd); +page_directory *pagedir_new(); //Creates a brand new empty page directory for a process, with kernel pages +void pagedir_delete(page_directory *pagedir); +page *pagedir_getPage(page_directory *pd, uint32_t address, int make); +void page_map(page *page, uint32_t frame, uint32_t user, uint32_t rw); +void page_unmap(page *page); +void page_unmapFree(page *page); + +uint32_t paging_fault(registers *regs); //returns a boolean : 1 if unhandled, 0 if ok #endif diff --git a/src/kernel/mem/seg.c b/src/kernel/mem/seg.c deleted file mode 100644 index 4a33db3..0000000 --- a/src/kernel/mem/seg.c +++ /dev/null @@ -1,113 +0,0 @@ -#include "seg.h" -#include "mem.h" -#include - -/* Call this function when mapping a segment to a page directory. - Calls the appropriate map method and updates the segment's and pagedir's information. */ -struct segment_map *seg_map(struct segment* seg, struct page_directory *pagedir, size_t offset) { - struct segment_map *sm = seg->map(seg, pagedir, offset); - if (sm == 0) return 0; - seg->mappings++; - sm->seg = seg; - sm->pagedir = pagedir; - sm->next = pagedir->mappedSegs; - pagedir->mappedSegs = sm; - return sm; -} - -/* Call this function when unmapping a segment from a page directory. - The segment will automatically be deleted if it is not mapped. - Calls the appropriate unmap method and updates the segment's and pagedir's information. */ -void seg_unmap(struct segment_map *map) { - map->seg->unmap(map); - if (map->pagedir->mappedSegs == map) { - map->pagedir->mappedSegs = map->pagedir->mappedSegs->next; - } else { - struct segment_map *m = map->pagedir->mappedSegs; - while (m->next != 0 && m->next != map) m = m->next; - if (m->next == map) m->next = map->next; - } - map->seg->mappings--; - if (map->seg->mappings == 0) { - map->seg->delete(map->seg); - kfree(map->seg->seg_data); - kfree(map->seg); - } - kfree (map); -} - -// ************************************ SIMPLESEG stuff ************* - -static struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir, size_t offset); -static void simpleseg_unmap(struct segment_map*); -static void simpleseg_delete(struct segment *seg); -static int simpleseg_handleFault(struct segment_map* map, size_t addr, int write); - -/* Call this when creating a simpleseg. - Creates the simpleseg structure and the segment structure and fills them up. */ -struct segment* simpleseg_make(size_t start, size_t len, int writable) { - struct simpleseg *ss = kmalloc(sizeof(struct simpleseg)); - struct segment *se = kmalloc(sizeof(struct segment)); - se->seg_data = ss; - se->mappings = 0; - se->map = simpleseg_map; - se->unmap = simpleseg_unmap; - se->delete = simpleseg_delete; - se->handle_fault = simpleseg_handleFault; - ss->writable = writable; ss->start = start; ss->len = len; - return se; -} - -/* For internal use only. Called when a simpleseg is mapped to a pagedirectory. */ -struct segment_map* simpleseg_map(struct segment* seg, struct page_directory* pagedir, size_t offset) { - struct segment_map *sm = kmalloc(sizeof(struct segment_map)); - sm->start = ((struct simpleseg*)(seg->seg_data))->start; - sm->len = ((struct simpleseg*)(seg->seg_data))->len; - return sm; -} - -/* For internal use only. Called when a simpleseg is unmapped. - Frees all the allocated pages. */ -void simpleseg_unmap(struct segment_map* sm) { - size_t i; - for (i = sm->start; i < sm->start + sm->len; i += 0x1000) { - page_unmapFree(pagedir_getPage(sm->pagedir, i, 0)); - } -} - -/* For internal use only. Handles a page fault. Can allocate and map a frame if necessary. */ -int simpleseg_handleFault(struct segment_map* sm, size_t addr, int write) { - struct simpleseg *ss = sm->seg->seg_data; - if (write && !ss->writable) return 1; - addr &= 0xFFFFF000; - struct page *p = pagedir_getPage(sm->pagedir, addr, 1); - if (p->frame != 0) return 1; - page_map(p, frame_alloc(), 1, ss->writable); - return 0; -} - -/* For internal use only. Called when the simpleseg is deleted. Does nothing. */ -void simpleseg_delete(struct segment* seg) { -} - -/* Call this to resize a simpleseg. Ajusts the size and frees pages if the new size is smaller.*/ -int simpleseg_resize(struct segment_map *map, size_t len) { - size_t i; - - if (map == 0) return -1; - if (map->seg->delete != simpleseg_delete) return -2; //check segment is a simpleseg - - struct simpleseg *s = (struct simpleseg*)map->seg->seg_data; - if (len & 0xFFF) len = (len & 0xFFFFF000) + 0x1000; - if (len < map->len) { - for (i = map->start + len; i < map->start + map->len; i += 0x1000) { - page_unmapFree(pagedir_getPage(map->pagedir, i, 0)); - } - map->len = len; - s->len = len; - } else if (len > map->len) { - map->len = len; - s->len = len; - } - return 0; -} diff --git a/src/kernel/mem/seg.cpp b/src/kernel/mem/seg.cpp new file mode 100644 index 0000000..c29e94e --- /dev/null +++ b/src/kernel/mem/seg.cpp @@ -0,0 +1,113 @@ +#include "seg.h" +#include "mem.h" +#include + +/* Call this function when mapping a segment to a page directory. + Calls the appropriate map method and updates the segment's and pagedir's information. */ +segment_map *seg_map(segment* seg, page_directory *pagedir, size_t offset) { + segment_map *sm = seg->map(seg, pagedir, offset); + if (sm == 0) return 0; + seg->mappings++; + sm->seg = seg; + sm->pagedir = pagedir; + sm->next = pagedir->mappedSegs; + pagedir->mappedSegs = sm; + return sm; +} + +/* Call this function when unmapping a segment from a page directory. + The segment will automatically be deleted if it is not mapped. + Calls the appropriate unmap method and updates the segment's and pagedir's information. */ +void seg_unmap(segment_map *map) { + map->seg->unmap(map); + if (map->pagedir->mappedSegs == map) { + map->pagedir->mappedSegs = map->pagedir->mappedSegs->next; + } else { + segment_map *m = map->pagedir->mappedSegs; + while (m->next != 0 && m->next != map) m = m->next; + if (m->next == map) m->next = map->next; + } + map->seg->mappings--; + if (map->seg->mappings == 0) { + map->seg->del(map->seg); + kfree(map->seg->seg_data); + kfree(map->seg); + } + kfree (map); +} + +// ************************************ SIMPLESEG stuff ************* + +static segment_map* simpleseg_map(segment* seg, page_directory* pagedir, size_t offset); +static void simpleseg_unmap(segment_map*); +static void simpleseg_delete(segment *seg); +static int simpleseg_handleFault(segment_map* map, size_t addr, int write); + +/* Call this when creating a simpleseg. + Creates the simpleseg structure and the segment structure and fills them up. */ +segment* simpleseg_make(size_t start, size_t len, int writable) { + simpleseg *ss = new simpleseg(); + segment *se = new segment(); + se->seg_data = ss; + se->mappings = 0; + se->map = simpleseg_map; + se->unmap = simpleseg_unmap; + se->del = simpleseg_delete; + se->handle_fault = simpleseg_handleFault; + ss->writable = writable; ss->start = start; ss->len = len; + return se; +} + +/* For internal use only. Called when a simpleseg is mapped to a pagedirectory. */ +segment_map* simpleseg_map(segment* seg, page_directory* pagedir, size_t offset) { + segment_map *sm = new segment_map(); + sm->start = ((simpleseg*)(seg->seg_data))->start; + sm->len = ((simpleseg*)(seg->seg_data))->len; + return sm; +} + +/* For internal use only. Called when a simpleseg is unmapped. + Frees all the allocated pages. */ +void simpleseg_unmap(segment_map* sm) { + size_t i; + for (i = sm->start; i < sm->start + sm->len; i += 0x1000) { + page_unmapFree(pagedir_getPage(sm->pagedir, i, 0)); + } +} + +/* For internal use only. Handles a page fault. Can allocate and map a frame if necessary. */ +int simpleseg_handleFault(segment_map* sm, size_t addr, int write) { + simpleseg *ss = (simpleseg*)sm->seg->seg_data; + if (write && !ss->writable) return 1; + addr &= 0xFFFFF000; + page *p = pagedir_getPage(sm->pagedir, addr, 1); + if (p->frame != 0) return 1; + page_map(p, frame_alloc(), 1, ss->writable); + return 0; +} + +/* For internal use only. Called when the simpleseg is deleted. Does nothing. */ +void simpleseg_delete(segment* seg) { +} + +/* Call this to resize a simpleseg. Ajusts the size and frees pages if the new size is smaller.*/ +int simpleseg_resize(segment_map *map, size_t len) { + size_t i; + + if (map == 0) return -1; + if (map->seg->del != simpleseg_delete) return -2; //check segment is a simpleseg + + simpleseg *s = (simpleseg*)map->seg->seg_data; + if (len & 0xFFF) len = (len & 0xFFFFF000) + 0x1000; + if (len < map->len) { + for (i = map->start + len; i < map->start + map->len; i += 0x1000) { + page_unmapFree(pagedir_getPage(map->pagedir, i, 0)); + } + map->len = len; + s->len = len; + } else if (len > map->len) { + map->len = len; + s->len = len; + } + return 0; +} diff --git a/src/kernel/mem/seg.h b/src/kernel/mem/seg.h index d37ba59..ea95dfa 100644 --- a/src/kernel/mem/seg.h +++ b/src/kernel/mem/seg.h @@ -12,23 +12,23 @@ struct segment { int mappings; // these 4 functions must not be used directly by anyone - struct segment_map* (*map)(struct segment* seg, struct page_directory* pagedir, size_t offset); - void (*unmap)(struct segment_map*); - void (*delete)(struct segment* seg); - int (*handle_fault)(struct segment_map* map, size_t addr, int write); //0 if ok, 1 if segfault + segment_map* (*map)(segment* seg, page_directory* pagedir, size_t offset); + void (*unmap)(segment_map*); + void (*del)(segment* seg); + int (*handle_fault)(segment_map* map, size_t addr, int write); //0 if ok, 1 if segfault }; struct segment_map { - struct segment* seg; - struct page_directory* pagedir; + segment* seg; + page_directory* pagedir; size_t start, len; - struct segment_map *next; + segment_map *next; }; //parameter offset in seg_map doesn't need to be used -struct segment_map *seg_map(struct segment* seg, struct page_directory* pagedir, size_t offset); -/* When unmapping a segment, the segment is deleted if it is not mapped anywhere anymore. */ -void seg_unmap(struct segment_map* map); +segment_map *seg_map(segment* seg, page_directory* pagedir, size_t offset); +// When unmapping a segment, the segment is deleted if it is not mapped anywhere anymore. +void seg_unmap(segment_map* map); /// ************************************* SIMPLESEG stuff ***************** @@ -37,7 +37,7 @@ struct simpleseg { size_t start, len; }; -struct segment* simpleseg_make(size_t start, size_t len, int writable); -int simpleseg_resize(struct segment_map *map, size_t len); +segment* simpleseg_make(size_t start, size_t len, int writable); +int simpleseg_resize(segment_map *map, size_t len); #endif diff --git a/src/kernel/task/idt.c b/src/kernel/task/idt.c deleted file mode 100644 index aed5ea8..0000000 --- a/src/kernel/task/idt.c +++ /dev/null @@ -1,219 +0,0 @@ -#include "idt.h" -#include -#include -#include -#include -#include "task.h" -#include "syscall.h" - -#include - -extern void isr0(); -extern void isr1(); -extern void isr2(); -extern void isr3(); -extern void isr4(); -extern void isr5(); -extern void isr6(); -extern void isr7(); -extern void isr8(); -extern void isr9(); -extern void isr10(); -extern void isr11(); -extern void isr12(); -extern void isr13(); -extern void isr14(); -extern void isr15(); -extern void isr16(); -extern void isr17(); -extern void isr18(); -extern void isr19(); -extern void isr20(); -extern void isr21(); -extern void isr22(); -extern void isr23(); -extern void isr24(); -extern void isr25(); -extern void isr26(); -extern void isr27(); -extern void isr28(); -extern void isr29(); -extern void isr30(); -extern void isr31(); - -extern void irq0(); -extern void irq1(); -extern void irq2(); -extern void irq3(); -extern void irq4(); -extern void irq5(); -extern void irq6(); -extern void irq7(); -extern void irq8(); -extern void irq9(); -extern void irq10(); -extern void irq11(); -extern void irq12(); -extern void irq13(); -extern void irq14(); -extern void irq15(); - -extern void syscall64(); - -extern void idt_flush(int32_t ptr); - -struct idt_entry idt_entries[256]; -struct idt_ptr idt_ptr; - -static int_callback irq_handlers[16] = {0}; -static struct irq_waiter { - struct thread *thread; - struct irq_waiter *next; -} *irq_wakeup[16] = {0}; - -/* Called in idt_.asm when an exception fires (interrupt 0 to 31). - Tries to handle the exception, panics if fails. */ -void idt_isrHandler(struct registers regs) { - if ((regs.int_no == 14 && paging_fault(®s) != 0) || regs.int_no != 14) { - if (tasking_handleException(®s) == 0) { - monitor_write("\nREALLY BAD THIS TIME\t\tUnhandled exception\t#"); - monitor_writeDec(regs.int_no); - monitor_write("\t@"); monitor_writeHex(regs.eip); - PANIC("Unhandled Exception"); - } - } -} - -/* Called in idt_.asm when an IRQ fires (interrupt 32 to 47) - Possibly wakes up a thread that was waiting, possibly calls a handler. */ -void idt_irqHandler(struct registers regs) { - uint32_t doSwitch = (regs.err_code == 0); //IRQ0 = timer - if (regs.err_code > 7) { - outb(0xA0, 0x20); - } - outb(0x20, 0x20); - while (irq_wakeup[regs.err_code] != 0) { - struct irq_waiter *tmp = irq_wakeup[regs.err_code]; - thread_wakeUp(tmp->thread); - irq_wakeup[regs.err_code] = tmp->next; - kfree(tmp); - doSwitch = 1; - } - if (irq_handlers[regs.err_code] != 0) { - irq_handlers[regs.err_code](®s); - } - if (doSwitch) schedule(); -} - -/* Called in idt_.asm on a system call (interrupt 64). - Calls the correct syscall handler (if any). */ -void idt_syscallHandler(struct registers regs) { - if (regs.eax < NUMBER_OF_SYSCALLS && syscalls[regs.eax] != 0) { - syscalls[regs.eax](®s); - } -} - -/* For internal use only. Sets up an entry of the IDT with given parameters. */ -static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { - idt_entries[num].base_lo = base & 0xFFFF; - idt_entries[num].base_hi = (base >> 16) & 0xFFFF; - - idt_entries[num].sel = sel; - idt_entries[num].always0 = 0; - idt_entries[num].flags = flags | 0x60; -} - -/* Remaps the IRQs. Sets up the IDT. */ -void idt_init() { - idt_ptr.limit = (sizeof(struct idt_entry) * 256) - 1; - idt_ptr.base = (uint32_t)&idt_entries; - - memset((uint8_t*)&idt_entries, 0, sizeof(struct idt_entry) * 256); - - //Remap the IRQ table - outb(0x20, 0x11); - outb(0xA0, 0x11); - outb(0x21, 0x20); - outb(0xA1, 0x28); - outb(0x21, 0x04); - outb(0xA1, 0x02); - outb(0x21, 0x01); - outb(0xA1, 0x01); - outb(0x21, 0x0); - outb(0xA1, 0x0); - - idt_setGate(0, (int32_t)isr0, 0x08, 0x8E); - idt_setGate(1, (int32_t)isr1, 0x08, 0x8E); - idt_setGate(2, (int32_t)isr2, 0x08, 0x8E); - idt_setGate(3, (int32_t)isr3, 0x08, 0x8E); - idt_setGate(4, (int32_t)isr4, 0x08, 0x8E); - idt_setGate(5, (int32_t)isr5, 0x08, 0x8E); - idt_setGate(6, (int32_t)isr6, 0x08, 0x8E); - idt_setGate(7, (int32_t)isr7, 0x08, 0x8E); - idt_setGate(8, (int32_t)isr8, 0x08, 0x8E); - idt_setGate(9, (int32_t)isr9, 0x08, 0x8E); - idt_setGate(10, (int32_t)isr10, 0x08, 0x8E); - idt_setGate(11, (int32_t)isr11, 0x08, 0x8E); - idt_setGate(12, (int32_t)isr12, 0x08, 0x8E); - idt_setGate(13, (int32_t)isr13, 0x08, 0x8E); - idt_setGate(14, (int32_t)isr14, 0x08, 0x8E); - idt_setGate(15, (int32_t)isr15, 0x08, 0x8E); - idt_setGate(16, (int32_t)isr16, 0x08, 0x8E); - idt_setGate(17, (int32_t)isr17, 0x08, 0x8E); - idt_setGate(18, (int32_t)isr18, 0x08, 0x8E); - idt_setGate(19, (int32_t)isr19, 0x08, 0x8E); - idt_setGate(20, (int32_t)isr20, 0x08, 0x8E); - idt_setGate(21, (int32_t)isr21, 0x08, 0x8E); - idt_setGate(22, (int32_t)isr22, 0x08, 0x8E); - idt_setGate(23, (int32_t)isr23, 0x08, 0x8E); - idt_setGate(24, (int32_t)isr24, 0x08, 0x8E); - idt_setGate(25, (int32_t)isr25, 0x08, 0x8E); - idt_setGate(26, (int32_t)isr26, 0x08, 0x8E); - idt_setGate(27, (int32_t)isr27, 0x08, 0x8E); - idt_setGate(28, (int32_t)isr28, 0x08, 0x8E); - idt_setGate(29, (int32_t)isr29, 0x08, 0x8E); - idt_setGate(30, (int32_t)isr30, 0x08, 0x8E); - idt_setGate(31, (int32_t)isr31, 0x08, 0x8E); - - idt_setGate(32, (int32_t)irq0, 0x08, 0x8E); - idt_setGate(33, (int32_t)irq1, 0x08, 0x8E); - idt_setGate(34, (int32_t)irq2, 0x08, 0x8E); - idt_setGate(35, (int32_t)irq3, 0x08, 0x8E); - idt_setGate(36, (int32_t)irq4, 0x08, 0x8E); - idt_setGate(37, (int32_t)irq5, 0x08, 0x8E); - idt_setGate(38, (int32_t)irq6, 0x08, 0x8E); - idt_setGate(39, (int32_t)irq7, 0x08, 0x8E); - idt_setGate(40, (int32_t)irq8, 0x08, 0x8E); - idt_setGate(41, (int32_t)irq9, 0x08, 0x8E); - idt_setGate(42, (int32_t)irq10, 0x08, 0x8E); - idt_setGate(43, (int32_t)irq11, 0x08, 0x8E); - idt_setGate(44, (int32_t)irq12, 0x08, 0x8E); - idt_setGate(45, (int32_t)irq13, 0x08, 0x8E); - idt_setGate(46, (int32_t)irq14, 0x08, 0x8E); - idt_setGate(47, (int32_t)irq15, 0x08, 0x8E); - - idt_setGate(64, (int32_t)syscall64, 0x08, 0x8E); - - idt_flush((int32_t)&idt_ptr); - - monitor_write("[IDT] "); -} - -/* Sets up an IRQ handler for given IRQ. */ -void idt_handleIrq(int number, int_callback func) { - if (number < 16 && number >= 0) { - irq_handlers[number] = func; - } -} - -/* Tells the IRQ handler to wake up the current thread when specified IRQ fires. */ -void idt_waitIrq(int number) { - if (number < 16 && number >= 0 && proc_priv() <= PL_KERNEL) { - struct irq_waiter *tmp = kmalloc(sizeof(struct irq_waiter)); - tmp->thread = current_thread; - tmp->next = irq_wakeup[number]; - irq_wakeup[number] = tmp; - - thread_goInactive(); - } -} diff --git a/src/kernel/task/idt.cpp b/src/kernel/task/idt.cpp new file mode 100644 index 0000000..ebc092d --- /dev/null +++ b/src/kernel/task/idt.cpp @@ -0,0 +1,223 @@ +#include "idt.h" +#include +#include +#include +#include +#include "task.h" +#include "syscall.h" + +#include + +extern "C" { + +extern void isr0(); +extern void isr1(); +extern void isr2(); +extern void isr3(); +extern void isr4(); +extern void isr5(); +extern void isr6(); +extern void isr7(); +extern void isr8(); +extern void isr9(); +extern void isr10(); +extern void isr11(); +extern void isr12(); +extern void isr13(); +extern void isr14(); +extern void isr15(); +extern void isr16(); +extern void isr17(); +extern void isr18(); +extern void isr19(); +extern void isr20(); +extern void isr21(); +extern void isr22(); +extern void isr23(); +extern void isr24(); +extern void isr25(); +extern void isr26(); +extern void isr27(); +extern void isr28(); +extern void isr29(); +extern void isr30(); +extern void isr31(); + +extern void irq0(); +extern void irq1(); +extern void irq2(); +extern void irq3(); +extern void irq4(); +extern void irq5(); +extern void irq6(); +extern void irq7(); +extern void irq8(); +extern void irq9(); +extern void irq10(); +extern void irq11(); +extern void irq12(); +extern void irq13(); +extern void irq14(); +extern void irq15(); + +extern void syscall64(); + +} + +extern "C" void idt_flush(int32_t ptr); + +idt_entry idt_entries[256]; +idt_ptr idt_ptr; + +static int_callback irq_handlers[16] = {0}; +static struct irq_waiter { + struct thread *thread; + irq_waiter *next; +} *irq_wakeup[16] = {0}; + +/* Called in idt_.asm when an exception fires (interrupt 0 to 31). + Tries to handle the exception, panics if fails. */ +extern "C" void idt_isrHandler(registers regs) { + if ((regs.int_no == 14 && paging_fault(®s) != 0) || regs.int_no != 14) { + if (tasking_handleException(®s) == 0) { + monitor_write("\nREALLY BAD THIS TIME\t\tUnhandled exception\t#"); + monitor_writeDec(regs.int_no); + monitor_write("\t@"); monitor_writeHex(regs.eip); + PANIC("Unhandled Exception"); + } + } +} + +/* Called in idt_.asm when an IRQ fires (interrupt 32 to 47) + Possibly wakes up a thread that was waiting, possibly calls a handler. */ +extern "C" void idt_irqHandler(registers regs) { + uint32_t doSwitch = (regs.err_code == 0); //IRQ0 = timer + if (regs.err_code > 7) { + outb(0xA0, 0x20); + } + outb(0x20, 0x20); + while (irq_wakeup[regs.err_code] != 0) { + irq_waiter *tmp = irq_wakeup[regs.err_code]; + thread_wakeUp(tmp->thread); + irq_wakeup[regs.err_code] = tmp->next; + kfree(tmp); + doSwitch = 1; + } + if (irq_handlers[regs.err_code] != 0) { + irq_handlers[regs.err_code](®s); + } + if (doSwitch) schedule(); +} + +/* Called in idt_.asm on a system call (interrupt 64). + Calls the correct syscall handler (if any). */ +extern "C" void idt_syscallHandler(registers regs) { + if (regs.eax < NUMBER_OF_SYSCALLS && syscalls[regs.eax] != 0) { + syscalls[regs.eax](®s); + } +} + +/* For internal use only. Sets up an entry of the IDT with given parameters. */ +static void idt_setGate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags) { + idt_entries[num].base_lo = base & 0xFFFF; + idt_entries[num].base_hi = (base >> 16) & 0xFFFF; + + idt_entries[num].sel = sel; + idt_entries[num].always0 = 0; + idt_entries[num].flags = flags | 0x60; +} + +/* Remaps the IRQs. Sets up the IDT. */ +void idt_init() { + idt_ptr.limit = (sizeof(idt_entry) * 256) - 1; + idt_ptr.base = (uint32_t)&idt_entries; + + memset((uint8_t*)&idt_entries, 0, sizeof(idt_entry) * 256); + + //Remap the IRQ table + outb(0x20, 0x11); + outb(0xA0, 0x11); + outb(0x21, 0x20); + outb(0xA1, 0x28); + outb(0x21, 0x04); + outb(0xA1, 0x02); + outb(0x21, 0x01); + outb(0xA1, 0x01); + outb(0x21, 0x0); + outb(0xA1, 0x0); + + idt_setGate(0, (int32_t)isr0, 0x08, 0x8E); + idt_setGate(1, (int32_t)isr1, 0x08, 0x8E); + idt_setGate(2, (int32_t)isr2, 0x08, 0x8E); + idt_setGate(3, (int32_t)isr3, 0x08, 0x8E); + idt_setGate(4, (int32_t)isr4, 0x08, 0x8E); + idt_setGate(5, (int32_t)isr5, 0x08, 0x8E); + idt_setGate(6, (int32_t)isr6, 0x08, 0x8E); + idt_setGate(7, (int32_t)isr7, 0x08, 0x8E); + idt_setGate(8, (int32_t)isr8, 0x08, 0x8E); + idt_setGate(9, (int32_t)isr9, 0x08, 0x8E); + idt_setGate(10, (int32_t)isr10, 0x08, 0x8E); + idt_setGate(11, (int32_t)isr11, 0x08, 0x8E); + idt_setGate(12, (int32_t)isr12, 0x08, 0x8E); + idt_setGate(13, (int32_t)isr13, 0x08, 0x8E); + idt_setGate(14, (int32_t)isr14, 0x08, 0x8E); + idt_setGate(15, (int32_t)isr15, 0x08, 0x8E); + idt_setGate(16, (int32_t)isr16, 0x08, 0x8E); + idt_setGate(17, (int32_t)isr17, 0x08, 0x8E); + idt_setGate(18, (int32_t)isr18, 0x08, 0x8E); + idt_setGate(19, (int32_t)isr19, 0x08, 0x8E); + idt_setGate(20, (int32_t)isr20, 0x08, 0x8E); + idt_setGate(21, (int32_t)isr21, 0x08, 0x8E); + idt_setGate(22, (int32_t)isr22, 0x08, 0x8E); + idt_setGate(23, (int32_t)isr23, 0x08, 0x8E); + idt_setGate(24, (int32_t)isr24, 0x08, 0x8E); + idt_setGate(25, (int32_t)isr25, 0x08, 0x8E); + idt_setGate(26, (int32_t)isr26, 0x08, 0x8E); + idt_setGate(27, (int32_t)isr27, 0x08, 0x8E); + idt_setGate(28, (int32_t)isr28, 0x08, 0x8E); + idt_setGate(29, (int32_t)isr29, 0x08, 0x8E); + idt_setGate(30, (int32_t)isr30, 0x08, 0x8E); + idt_setGate(31, (int32_t)isr31, 0x08, 0x8E); + + idt_setGate(32, (int32_t)irq0, 0x08, 0x8E); + idt_setGate(33, (int32_t)irq1, 0x08, 0x8E); + idt_setGate(34, (int32_t)irq2, 0x08, 0x8E); + idt_setGate(35, (int32_t)irq3, 0x08, 0x8E); + idt_setGate(36, (int32_t)irq4, 0x08, 0x8E); + idt_setGate(37, (int32_t)irq5, 0x08, 0x8E); + idt_setGate(38, (int32_t)irq6, 0x08, 0x8E); + idt_setGate(39, (int32_t)irq7, 0x08, 0x8E); + idt_setGate(40, (int32_t)irq8, 0x08, 0x8E); + idt_setGate(41, (int32_t)irq9, 0x08, 0x8E); + idt_setGate(42, (int32_t)irq10, 0x08, 0x8E); + idt_setGate(43, (int32_t)irq11, 0x08, 0x8E); + idt_setGate(44, (int32_t)irq12, 0x08, 0x8E); + idt_setGate(45, (int32_t)irq13, 0x08, 0x8E); + idt_setGate(46, (int32_t)irq14, 0x08, 0x8E); + idt_setGate(47, (int32_t)irq15, 0x08, 0x8E); + + idt_setGate(64, (int32_t)syscall64, 0x08, 0x8E); + + idt_flush((int32_t)&idt_ptr); + + monitor_write("[IDT] "); +} + +/* Sets up an IRQ handler for given IRQ. */ +void idt_handleIrq(int number, int_callback func) { + if (number < 16 && number >= 0) { + irq_handlers[number] = func; + } +} + +/* Tells the IRQ handler to wake up the current thread when specified IRQ fires. */ +void idt_waitIrq(int number) { + if (number < 16 && number >= 0 && proc_priv() <= PL_KERNEL) { + irq_waiter *tmp = new irq_waiter(); + tmp->thread = current_thread; + tmp->next = irq_wakeup[number]; + irq_wakeup[number] = tmp; + + thread_goInactive(); + } +} diff --git a/src/kernel/task/idt.h b/src/kernel/task/idt.h index 1ac03e2..849418e 100644 --- a/src/kernel/task/idt.h +++ b/src/kernel/task/idt.h @@ -29,7 +29,7 @@ struct registers { uint32_t eip, cs, eflags, useresp, ss; // Pushed by the processor automatically. }; -typedef void (*int_callback)(struct registers*); +typedef void (*int_callback)(registers*); void idt_init(); void idt_handleIrq(int number, int_callback func); //Set IRQ handler diff --git a/src/kernel/task/sched.c b/src/kernel/task/sched.c deleted file mode 100644 index aa41d5b..0000000 --- a/src/kernel/task/sched.c +++ /dev/null @@ -1,50 +0,0 @@ -#include "sched.h" -#include -#include - -// Lower priority numbers have high priority. Priorities must start at 0. -#define PRIORITIES 3 // we have 4 priority levels -#define PRIORITY(t) (t->process->privilege) //get priority for a thread - -extern struct thread *idle_thread; - -static struct thread *queue[PRIORITIES] = {0}, *last[PRIORITIES] = {0}; - -/* For internal use only. Enqueues specified thread in specified priority queue. */ -static void sched_enqueueIn(struct thread *t, int qid) { - t->queue_next = 0; - if (queue[qid] == 0) { - queue[qid] = last[qid] = t; - } else { - last[qid]->queue_next = t; - last[qid] = t; - } -} - -/* For internal use only. Pops a thread from specified queue, if available. */ -static struct thread *sched_dequeueFrom(int qid) { - if (queue[qid] == 0) return 0; - struct thread *it = queue[qid]; - ASSERT((it->queue_next == 0 && it == last[qid]) || it != last[qid]); - queue[qid] = it->queue_next; - if (queue[qid] == 0) last[qid] = 0; - return it; -} - -/* Used by task.c. Enqueus a thread in the corresponding priority queue. */ -void sched_enqueue(struct thread *t) { - if (t == idle_thread) return; - sched_enqueueIn(t, PRIORITY(t)); -} - -/* Used by task.c. Pops a thread from the lowest priority non-empty queue. */ -struct thread *sched_dequeue() { - struct thread *it = 0; - int i; - for (i = 0; i < PRIORITIES; i++) { - it = sched_dequeueFrom(i); - if (it != 0) break; - } - if (it == 0) return idle_thread; - return it; -} diff --git a/src/kernel/task/sched.cpp b/src/kernel/task/sched.cpp new file mode 100644 index 0000000..e773e97 --- /dev/null +++ b/src/kernel/task/sched.cpp @@ -0,0 +1,50 @@ +#include "sched.h" +#include +#include + +// Lower priority numbers have high priority. Priorities must start at 0. +#define PRIORITIES 3 // we have 4 priority levels +#define PRIORITY(t) (t->process->privilege) //get priority for a thread + +extern thread *idle_thread; + +static thread *queue[PRIORITIES] = {0}, *last[PRIORITIES] = {0}; + +/* For internal use only. Enqueues specified thread in specified priority queue. */ +static void sched_enqueueIn(thread *t, int qid) { + t->queue_next = 0; + if (queue[qid] == 0) { + queue[qid] = last[qid] = t; + } else { + last[qid]->queue_next = t; + last[qid] = t; + } +} + +/* For internal use only. Pops a thread from specified queue, if available. */ +static thread *sched_dequeueFrom(int qid) { + if (queue[qid] == 0) return 0; + thread *it = queue[qid]; + ASSERT((it->queue_next == 0 && it == last[qid]) || it != last[qid]); + queue[qid] = it->queue_next; + if (queue[qid] == 0) last[qid] = 0; + return it; +} + +/* Used by task.c. Enqueus a thread in the corresponding priority queue. */ +void sched_enqueue(thread *t) { + if (t == idle_thread) return; + sched_enqueueIn(t, PRIORITY(t)); +} + +/* Used by task.c. Pops a thread from the lowest priority non-empty queue. */ +thread *sched_dequeue() { + thread *it = 0; + int i; + for (i = 0; i < PRIORITIES; i++) { + it = sched_dequeueFrom(i); + if (it != 0) break; + } + if (it == 0) return idle_thread; + return it; +} diff --git a/src/kernel/task/sched.h b/src/kernel/task/sched.h index 1233a44..7d0dcd3 100644 --- a/src/kernel/task/sched.h +++ b/src/kernel/task/sched.h @@ -3,7 +3,7 @@ #include "task.h" -void sched_enqueue(struct thread *t); -struct thread *sched_dequeue(); +void sched_enqueue(thread *t); +thread *sched_dequeue(); #endif diff --git a/src/kernel/task/syscall.c b/src/kernel/task/syscall.c deleted file mode 100644 index bd27eba..0000000 --- a/src/kernel/task/syscall.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "syscall.h" -#include "task.h" -#include - -#define CALL0(name, scname) static void scname(struct registers* r) { r->eax = name(); } -#define CALL1(name, scname) static void scname(struct registers* r) { \ - r->eax = name(r->ebx); } -#define CALL2(name, scname) static void scname(struct registers* r) { \ - r->eax = name(r->ebx, r->ecx); } -#define CALL3(name, scname) static void scname(struct registers* r) { \ - r->eax = name(r->ebx, r->ecx, r->edx); } -#define CALL0V(name, scname) static void scname(struct registers* r) { name(); } -#define CALL1V(name, scname) static void scname(struct registers* r) { name(r->ebx); } -#define CALL2V(name, scname) static void scname(struct registers* r) { name(r->ebx, r->ecx); } -#define CALL3V(name, scname) static void scname(struct registers* r) { name(r->ebx, r->ecx, r->edx); } -#define CALL4V(name, scname) static void scname(struct registers* r) { name(r->ebx, r->ecx, r->edx, r->esi); } - -CALL0V(thread_exit, thread_exit_sc); -CALL0V(schedule, schedule_sc); -CALL1V(thread_sleep, thread_sleep_sc); -CALL1V(process_exit, process_exit_sc); -CALL1(monitor_write, printk_sc); -CALL1V(idt_waitIrq, irq_wait_sc); -CALL0(proc_priv, proc_priv_sc); -CALL1(process_sbrk, proc_sbrk_sc); -CALL1V(process_brk, proc_brk_sc); - -static void thread_new_sc(struct registers* r) { - cli(); - thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx, (void*)r->edx); - sti(); -} - -int_callback syscalls[NUMBER_OF_SYSCALLS] = { - thread_exit_sc, //0 - schedule_sc, - thread_sleep_sc, - process_exit_sc, - printk_sc, - thread_new_sc, //5 - irq_wait_sc, - proc_priv_sc, - proc_sbrk_sc, - proc_brk_sc, - 0 }; diff --git a/src/kernel/task/syscall.cpp b/src/kernel/task/syscall.cpp new file mode 100644 index 0000000..6880745 --- /dev/null +++ b/src/kernel/task/syscall.cpp @@ -0,0 +1,50 @@ +#include "syscall.h" +#include "task.h" +#include "timer.h" +#include +#include + +#define CALL0(name, scname) static void scname(registers* r) { r->eax = name(); } +#define CALL1(name, scname) static void scname(registers* r) { \ + r->eax = name(r->ebx); } +#define CALL2(name, scname) static void scname(registers* r) { \ + r->eax = name(r->ebx, r->ecx); } +#define CALL3(name, scname) static void scname(registers* r) { \ + r->eax = name(r->ebx, r->ecx, r->edx); } +#define CALL0V(name, scname) static void scname(registers* r) { name(); } +#define CALL1V(name, scname) static void scname(registers* r) { name(r->ebx); } +#define CALL2V(name, scname) static void scname(registers* r) { name(r->ebx, r->ecx); } +#define CALL3V(name, scname) static void scname(registers* r) { name(r->ebx, r->ecx, r->edx); } +#define CALL4V(name, scname) static void scname(registers* r) { name(r->ebx, r->ecx, r->edx, r->esi); } + +CALL0V(thread_exit, thread_exit_sc); +CALL0V(schedule, schedule_sc); +CALL1V(thread_sleep, thread_sleep_sc); +CALL1V(process_exit, process_exit_sc); +CALL1V(idt_waitIrq, irq_wait_sc); +CALL0(proc_priv, proc_priv_sc); +CALL1(process_sbrk, proc_sbrk_sc); +CALL1V(process_brk, proc_brk_sc); + +static void printk_sc(registers *r) { + monitor_write((char*)r->ebx); +} + +static void thread_new_sc(registers* r) { + cli(); + thread_new(current_thread->process, (thread_entry)r->ebx, (void*)r->ecx, (void*)r->edx); + sti(); +} + +int_callback syscalls[NUMBER_OF_SYSCALLS] = { + thread_exit_sc, //0 + schedule_sc, + thread_sleep_sc, + process_exit_sc, + printk_sc, + thread_new_sc, //5 + irq_wait_sc, + proc_priv_sc, + proc_sbrk_sc, + proc_brk_sc, + 0 }; diff --git a/src/kernel/task/task.c b/src/kernel/task/task.c deleted file mode 100644 index 9d98165..0000000 --- a/src/kernel/task/task.c +++ /dev/null @@ -1,410 +0,0 @@ -#include "task.h" -#include "sched.h" -#include -#include -#include -#include -#include -#include "timer.h" - -#define KSTACKSIZE 0x8000 - -//Static routines for handling threads exiting and all cleanup -static void thread_exit_stackJmp(uint32_t reason); -static void thread_exit2(uint32_t reason); -static void thread_delete(struct thread *th); -static void process_delete(struct process *pr); - -//From task_.asm -extern uint32_t read_eip(); -extern void task_idle(void*); - -static uint32_t nextpid = 1; -struct process *processes = 0, *kernel_process; -struct thread *current_thread = 0, *idle_thread = 0; - -uint32_t tasking_tmpStack[KSTACKSIZE]; - -/* Sets up tasking. Called by kmain on startup. - Creates a kernel process and an IDLE thread in it. */ -void tasking_init() { - cli(); - kernel_process = kmalloc(sizeof(struct process)); //This process must be hidden to users - kernel_process->pid = kernel_process->uid = kernel_process->thread_count = 0; - kernel_process->privilege = PL_KERNEL; - kernel_process->parent = kernel_process; - kernel_process->pagedir = kernel_pagedir; - kernel_process->next = 0; - kernel_process->threads = 0; - current_thread = 0; - idle_thread = thread_new(kernel_process, task_idle, 0, 0); - sti(); - monitor_write("[Tasking] "); -} - -/* Called by the paging functions when a page table is allocated in the kernel space (>K_HIGHHALF_ADDR). - Updates the page directories of all the processes. */ -void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablephysical) { - if (idx < FIRST_KERNEL_PAGETABLE) return; - struct process* it = processes; - while (it != 0) { - it->pagedir->tables[idx] = table; - it->pagedir->tablesPhysical[idx] = tablephysical; - it = it->next; - } -} - -/* Called when a timer IRQ fires. Does a context switch. */ -void schedule() { - if (processes == 0) PANIC("No processes are running !"); - asm volatile("cli"); - - uint32_t esp, ebp, eip; - - asm volatile("mov %%esp, %0" : "=r"(esp)); - asm volatile("mov %%ebp, %0" : "=r"(ebp)); - eip = read_eip(); - - if (eip == 0x12345) { - return; - } - - if (current_thread != 0) { - current_thread->esp = esp; - current_thread->ebp = ebp; - current_thread->eip = eip; - if (current_thread->state == TS_RUNNING) sched_enqueue(current_thread); - } - - current_thread = sched_dequeue(); - ASSERT(current_thread != 0); - - pagedir_switch(current_thread->process->pagedir); - - gdt_setKernelStack(((uint32_t)current_thread->kernelStack_addr) + current_thread->kernelStack_size); - - 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)); -} - -/* Called when an exception happens. Provides a stack trace if it was in kernel land. - Ends the thread for most exceptions, ends the whole process for page faults. */ -uint32_t tasking_handleException(struct registers *regs) { - if (current_thread == 0) return 0; //No tasking yet - NL; WHERE; monitor_write("exception:`"); - char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint", - "Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault", - "Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault", - "Page Fault","Unknown Interrupt","Coprocessor Fault","Alignment Check","Machine Check"}; - monitor_write(exception_messages[regs->int_no]); - monitor_write("'\teip:"); monitor_writeHex(regs->eip); - if (regs->eip >= K_HIGHHALF_ADDR) { - monitor_write("\n Exception stack trace :\n"); - stack_trace(regs->ebp); - PANIC("Kernel error'd."); - } - if (regs->int_no == 14) { - monitor_write("\n>>> Process exiting.\n"); - thread_exit_stackJmp(EX_PR_EXCEPTION); - } else { - monitor_write("\n>>> Thread exiting.\n"); - thread_exit_stackJmp(EX_TH_EXCEPTION); - } - PANIC("This should never have happened. Please report this."); - return 0; -} - -/* Puts the current thread in an inactive state. */ -void thread_goInactive() { - current_thread->state = TS_WAKEWAIT; - schedule(); -} - -/* Wakes up the given thread. */ -void thread_wakeUp(struct thread* t) { - if (t->state == TS_WAKEWAIT) { - t->state = TS_RUNNING; - sched_enqueue(t); - } -} - -/* Returns the privilege level of the current process. */ -int proc_priv() { - if (current_thread == 0 || current_thread->process == 0) return PL_UNKNOWN; - return current_thread->process->privilege; -} - -/* For internal use only. Called by thread_exit_stackJmp on a stack that will not be deleted. - Exits current thread or process, depending on the reason. */ -void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h - /* - * if reason == EX_TH_NORMAL, it is just one thread exiting because it has to - * if reason == EX_TH_EXCEPTION, it is just one thread exiting because of an exception - * if reason is none of the two cases above, it is the whole process exiting (with error code = reason) - */ - struct thread *th = current_thread; - if (th == 0 || th->process == 0) goto retrn; - struct process *pr = th->process; - if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->thread_count > 1) { - thread_delete(th); - } else { - process_delete(pr); - } - retrn: - sti(); - schedule(); -} - -/* For internal use only. Called by thread_exit and process_exit. - Switches to a stack that will not be deleted when current thread is deleted. */ -void thread_exit_stackJmp(uint32_t reason) { - cli(); - uint32_t *stack; - stack = tasking_tmpStack + (KSTACKSIZE / 4); - stack--; *stack = reason; - stack--; *stack = 0; - asm volatile(" \ - mov %0, %%esp; \ - mov %1, %%ebp; \ - mov %2, %%ecx; \ - mov %3, %%cr3; \ - jmp *%%ecx;" : : - "r"(stack), "r"(stack), "r"(thread_exit2), "r"(kernel_pagedir->physicalAddr)); -} - -/* System call. Exit the current thread. */ -void thread_exit() { - thread_exit_stackJmp(EX_TH_NORMAL); -} - -/* System call. Exit the current process. */ -void process_exit(size_t retval) { - if (retval == EX_TH_NORMAL || retval == EX_TH_EXCEPTION) retval = EX_PR_EXCEPTION; - thread_exit_stackJmp(retval); -} - -/* For internal use only. This is called when a newly created thread first runs - (its address is the value given for EIP). - It switches to user mode if necessary and calls the entry point. */ -static void thread_run(void* u_esp, struct thread *thread, thread_entry entry_point, void *data) { - pagedir_switch(thread->process->pagedir); - if (thread->process->privilege >= PL_USER) { //User mode ! - uint32_t *stack = u_esp; - - stack--; *stack = (uint32_t)data; - stack--; *stack = 0; - size_t esp = (size_t)stack, eip = (size_t)entry_point; - //Setup a false structure for returning from an interrupt : - //value for esp is in ebx, for eip is in ecx - //- update data segments to 0x23 = user data segment with RPL=3 - //- push value for ss : 0x23 (user data seg rpl3) - //- push value for esp - //- push flags - //- update flags, set IF = 1 (interrupts flag) - //- push value for cs : 0x1B = user code segment with RPL=3 - //- push eip - //- return from fake interrupt - asm volatile(" \ - mov $0x23, %%ax; \ - mov %%ax, %%ds; \ - mov %%ax, %%es; \ - mov %%ax, %%fs; \ - mov %%ax, %%gs; \ - \ - pushl $0x23; \ - pushl %%ebx; \ - pushf; \ - pop %%eax; \ - or $0x200, %%eax; \ - push %%eax; \ - pushl $0x1B; \ - push %%ecx; \ - iret; \ - " : : "b"(esp), "c"(eip)); - } else { - asm volatile("sti"); - entry_point(data); - } - thread_exit(0); -} - -/* Creates a new thread for given process. - Allocates a kernel stack and a user stack if necessary. - Sets up the kernel stack for values to be passed to thread_run. */ -struct thread *thread_new(struct process *proc, thread_entry entry_point, void *data, void *u_esp) { - struct thread *t = kmalloc(sizeof(struct thread)); - t->process = proc; - t->next = 0; - proc->thread_count++; - - if (u_esp == 0) u_esp = (void*)proc->stack; - - 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 = (uint32_t)u_esp; - stack--; *stack = 0; - t->esp = (uint32_t)stack; - t->ebp = t->esp + 8; - t->eip = (uint32_t)thread_run; - - t->state = TS_RUNNING; - sched_enqueue(t); - - if (proc->threads == 0) { - proc->threads = t; - } else { - struct thread *i = proc->threads; - while (i->next != 0) i = i->next; - i->next = t; - } - return t; -} - -/* Creates a new process. Creates a struct process and fills it up. */ -struct process *process_new(struct process* parent, uint32_t uid, uint32_t privilege) { - struct process* p = kmalloc(sizeof(struct process)); - p->pid = (nextpid++); - p->uid = uid; - p->thread_count = 0; - p->threads = 0; - p->privilege = privilege; - p->parent = parent; - p->pagedir = pagedir_new(); - p->next = processes; - p->data = 0; - p->dataseg = 0; - - p->stack = 0; - if (p->privilege >= PL_USER) { //We are running in user mode - size_t stacksBottom = K_HIGHHALF_ADDR - 0x01000000; - seg_map(simpleseg_make(stacksBottom, USER_STACK_SIZE, 1), p->pagedir, 0); - p->stack = stacksBottom + USER_STACK_SIZE - 4; - } - - processes = p; - return p; -} - -/* Deletes given thread, freeing the stack(s). */ -static void thread_delete(struct thread *th) { - if (th->process->threads == th) { - th->process->threads = th->next; - } else { - struct thread *it = th->process->threads; - while (it) { - if (it->next == th) { - it->next = th->next; - break; - } - it = it->next; - } - } - if (current_thread == th) current_thread = 0; - th->process->thread_count--; - kfree(th->kernelStack_addr); - kfree(th); -} - -/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */ -static void process_delete(struct process *pr) { - struct thread *it = pr->threads; - while (it != 0) { - thread_delete(it); - it = it->next; - } - if (processes == pr) { - processes = pr->next; - } else { - struct process *it = processes; - while (it) { - if (it->next == pr) { - it->next = pr->next; - break; - } - it = it->next; - } - } - pagedir_delete(pr->pagedir); - kfree(pr); -} - -/* System call. Called by the app to define the place for the heap. */ -/*int process_setheapseg(size_t start, size_t end) { //syscall - struct process *p = current_thread->process; - if (start >= K_HIGHHALF_ADDR || end >= K_HIGHHALF_ADDR) return -1; - if (p->heapseg == 0) { - struct segment *s = simpleseg_make(start, end - start, 1); - if (s == 0) return -5; - p->heapseg = seg_map(s, p->pagedir, 0); - if (p->heapseg == 0) return -1; - return 0; - } else if (p->heapseg->start != start) { - seg_unmap(p->heapseg); - struct segment *s = simpleseg_make(start, end - start, 1); - if (s == 0) return -5; - p->heapseg = seg_map(s, p->pagedir, 0); - if (p->heapseg == 0) return -1; - return 0; - } else { - return simpleseg_resize(p->heapseg, end - start); - } -}*/ - -size_t process_sbrk(size_t size) { - struct process *p = current_thread->process; - if (p->data == 0) return -1; - ASSERT(p->data < K_HIGHHALF_ADDR); - if (p->data + size >= K_HIGHHALF_ADDR) return -1; - - size_t ret; - if (p->dataseg == 0) { - size_t start = p->data; - if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000; - size_t end = start + size; - if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; - - struct segment *s = simpleseg_make(start, end - start, 1); - if (s == 0) return -5; - p->dataseg = seg_map(s, p->pagedir, 0); - if (p->dataseg == 0) return -1; - - ret = start; - p->data = start + size; - } else { - size_t start = p->dataseg->start; - size_t end = p->data + size; - if (end <= start) return -1; - - if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; - simpleseg_resize(p->dataseg, end - start); - - ret = p->data; - p->data += size; - } - /* (DBG) monitor_write("(sbrk "); - monitor_writeHex(size); - monitor_write(" "); - monitor_writeHex(ret); - monitor_write(")"); */ - return ret; -} - -void process_brk(size_t ptr) { - struct process *p = current_thread->process; - - ASSERT(ptr < K_HIGHHALF_ADDR); - process_sbrk(ptr - p->data); -} - diff --git a/src/kernel/task/task.cpp b/src/kernel/task/task.cpp new file mode 100644 index 0000000..b7c8f45 --- /dev/null +++ b/src/kernel/task/task.cpp @@ -0,0 +1,411 @@ +#include "task.h" +#include "sched.h" +#include +#include +#include +#include +#include +#include "timer.h" + +#define KSTACKSIZE 0x8000 + +//Static routines for handling threads exiting and all cleanup +static void thread_exit_stackJmp(uint32_t reason); +static void thread_exit2(uint32_t reason); +static void thread_delete(thread *th); +static void process_delete(process *pr); + +//From task_.asm +extern "C" uint32_t read_eip(); +extern "C" void task_idle(void*); + +static uint32_t nextpid = 1; +process *processes = 0, *kernel_process; +thread *current_thread = 0, *idle_thread = 0; + +uint32_t tasking_tmpStack[KSTACKSIZE]; + +/* Sets up tasking. Called by kmain on startup. + Creates a kernel process and an IDLE thread in it. */ +void tasking_init() { + cli(); + kernel_process = new process(); //This process must be hidden to users + kernel_process->pid = kernel_process->uid = kernel_process->thread_count = 0; + kernel_process->privilege = PL_KERNEL; + kernel_process->parent = kernel_process; + kernel_process->pagedir = kernel_pagedir; + kernel_process->next = 0; + kernel_process->threads = 0; + current_thread = 0; + idle_thread = thread_new(kernel_process, task_idle, 0, 0); + sti(); + monitor_write("[Tasking] "); +} + +/* Called by the paging functions when a page table is allocated in the kernel space (>K_HIGHHALF_ADDR). + Updates the page directories of all the processes. */ +void tasking_updateKernelPagetable(uint32_t idx, page_table *table, uint32_t tablephysical) { + if (idx < FIRST_KERNEL_PAGETABLE) return; + process* it = processes; + while (it != 0) { + it->pagedir->tables[idx] = table; + it->pagedir->tablesPhysical[idx] = tablephysical; + it = it->next; + } +} + +/* Called when a timer IRQ fires. Does a context switch. */ +void schedule() { + if (processes == 0) PANIC("No processes are running !"); + asm volatile("cli"); + + uint32_t esp, ebp, eip; + + asm volatile("mov %%esp, %0" : "=r"(esp)); + asm volatile("mov %%ebp, %0" : "=r"(ebp)); + eip = read_eip(); + + if (eip == 0x12345) { + return; + } + + if (current_thread != 0) { + current_thread->esp = esp; + current_thread->ebp = ebp; + current_thread->eip = eip; + if (current_thread->state == TS_RUNNING) sched_enqueue(current_thread); + } + + current_thread = sched_dequeue(); + ASSERT(current_thread != 0); + + pagedir_switch(current_thread->process->pagedir); + + gdt_setKernelStack(((uint32_t)current_thread->kernelStack_addr) + current_thread->kernelStack_size); + + 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)); +} + +/* Called when an exception happens. Provides a stack trace if it was in kernel land. + Ends the thread for most exceptions, ends the whole process for page faults. */ +uint32_t tasking_handleException(registers *regs) { + if (current_thread == 0) return 0; //No tasking yet + NL; WHERE; monitor_write("exception:`"); + char *exception_messages[] = {"Division By Zero","Debug","Non Maskable Interrupt","Breakpoint", + "Into Detected Overflow","Out of Bounds","Invalid Opcode","No Coprocessor", "Double Fault", + "Coprocessor Segment Overrun","Bad TSS","Segment Not Present","Stack Fault","General Protection Fault", + "Page Fault","Unknown Interrupt","Coprocessor Fault","Alignment Check","Machine Check"}; + monitor_write(exception_messages[regs->int_no]); + monitor_write("'\teip:"); monitor_writeHex(regs->eip); + if (regs->eip >= K_HIGHHALF_ADDR) { + monitor_write("\n Exception stack trace :\n"); + stack_trace(regs->ebp); + PANIC("Kernel error'd."); + } + if (regs->int_no == 14) { + monitor_write("\n>>> Process exiting.\n"); + thread_exit_stackJmp(EX_PR_EXCEPTION); + } else { + monitor_write("\n>>> Thread exiting.\n"); + thread_exit_stackJmp(EX_TH_EXCEPTION); + } + PANIC("This should never have happened. Please report this."); + return 0; +} + +/* Puts the current thread in an inactive state. */ +void thread_goInactive() { + current_thread->state = TS_WAKEWAIT; + schedule(); +} + +/* Wakes up the given thread. */ +void thread_wakeUp(thread* t) { + if (t->state == TS_WAKEWAIT) { + t->state = TS_RUNNING; + sched_enqueue(t); + } +} + +/* Returns the privilege level of the current process. */ +int proc_priv() { + if (current_thread == 0 || current_thread->process == 0) return PL_UNKNOWN; + return current_thread->process->privilege; +} + +/* For internal use only. Called by thread_exit_stackJmp on a stack that will not be deleted. + Exits current thread or process, depending on the reason. */ +void thread_exit2(uint32_t reason) { //See EX_TH_* defines in task.h + /* + * if reason == EX_TH_NORMAL, it is just one thread exiting because it has to + * if reason == EX_TH_EXCEPTION, it is just one thread exiting because of an exception + * if reason is none of the two cases above, it is the whole process exiting (with error code = reason) + */ + thread *th = current_thread; + process* pr; + if (th == 0 || th->process == 0) goto retrn; + pr = th->process; + if ((reason == EX_TH_NORMAL || reason == EX_TH_EXCEPTION) && pr->thread_count > 1) { + thread_delete(th); + } else { + process_delete(pr); + } + retrn: + sti(); + schedule(); +} + +/* For internal use only. Called by thread_exit and process_exit. + Switches to a stack that will not be deleted when current thread is deleted. */ +void thread_exit_stackJmp(uint32_t reason) { + cli(); + uint32_t *stack; + stack = tasking_tmpStack + (KSTACKSIZE / 4); + stack--; *stack = reason; + stack--; *stack = 0; + asm volatile(" \ + mov %0, %%esp; \ + mov %1, %%ebp; \ + mov %2, %%ecx; \ + mov %3, %%cr3; \ + jmp *%%ecx;" : : + "r"(stack), "r"(stack), "r"(thread_exit2), "r"(kernel_pagedir->physicalAddr)); +} + +/* System call. Exit the current thread. */ +void thread_exit() { + thread_exit_stackJmp(EX_TH_NORMAL); +} + +/* System call. Exit the current process. */ +void process_exit(size_t retval) { + if (retval == EX_TH_NORMAL || retval == EX_TH_EXCEPTION) retval = EX_PR_EXCEPTION; + thread_exit_stackJmp(retval); +} + +/* For internal use only. This is called when a newly created thread first runs + (its address is the value given for EIP). + It switches to user mode if necessary and calls the entry point. */ +static void thread_run(void* u_esp, thread *thread, thread_entry entry_point, void *data) { + pagedir_switch(thread->process->pagedir); + if (thread->process->privilege >= PL_USER) { //User mode ! + uint32_t *stack = (uint32_t*)u_esp; + + stack--; *stack = (uint32_t)data; + stack--; *stack = 0; + size_t esp = (size_t)stack, eip = (size_t)entry_point; + //Setup a false structure for returning from an interrupt : + //value for esp is in ebx, for eip is in ecx + //- update data segments to 0x23 = user data segment with RPL=3 + //- push value for ss : 0x23 (user data seg rpl3) + //- push value for esp + //- push flags + //- update flags, set IF = 1 (interrupts flag) + //- push value for cs : 0x1B = user code segment with RPL=3 + //- push eip + //- return from fake interrupt + asm volatile(" \ + mov $0x23, %%ax; \ + mov %%ax, %%ds; \ + mov %%ax, %%es; \ + mov %%ax, %%fs; \ + mov %%ax, %%gs; \ + \ + pushl $0x23; \ + pushl %%ebx; \ + pushf; \ + pop %%eax; \ + or $0x200, %%eax; \ + push %%eax; \ + pushl $0x1B; \ + push %%ecx; \ + iret; \ + " : : "b"(esp), "c"(eip)); + } else { + asm volatile("sti"); + entry_point(data); + } + thread_exit(); +} + +/* Creates a new thread for given process. + Allocates a kernel stack and a user stack if necessary. + Sets up the kernel stack for values to be passed to thread_run. */ +thread *thread_new(process *proc, thread_entry entry_point, void *data, void *u_esp) { + thread *t = new thread(); + t->process = proc; + t->next = 0; + proc->thread_count++; + + if (u_esp == 0) u_esp = (void*)proc->stack; + + 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 = (uint32_t)u_esp; + stack--; *stack = 0; + t->esp = (uint32_t)stack; + t->ebp = t->esp + 8; + t->eip = (uint32_t)thread_run; + + t->state = TS_RUNNING; + sched_enqueue(t); + + if (proc->threads == 0) { + proc->threads = t; + } else { + thread *i = proc->threads; + while (i->next != 0) i = i->next; + i->next = t; + } + return t; +} + +/* Creates a new process. Creates a struct process and fills it up. */ +process *process_new(process* parent, uint32_t uid, uint32_t privilege) { + process* p = new process(); + p->pid = (nextpid++); + p->uid = uid; + p->thread_count = 0; + p->threads = 0; + p->privilege = privilege; + p->parent = parent; + p->pagedir = pagedir_new(); + p->next = processes; + p->data = 0; + p->dataseg = 0; + + p->stack = 0; + if (p->privilege >= PL_USER) { //We are running in user mode + size_t stacksBottom = K_HIGHHALF_ADDR - 0x01000000; + seg_map(simpleseg_make(stacksBottom, USER_STACK_SIZE, 1), p->pagedir, 0); + p->stack = stacksBottom + USER_STACK_SIZE - 4; + } + + processes = p; + return p; +} + +/* Deletes given thread, freeing the stack(s). */ +static void thread_delete(thread *th) { + if (th->process->threads == th) { + th->process->threads = th->next; + } else { + thread *it = th->process->threads; + while (it) { + if (it->next == th) { + it->next = th->next; + break; + } + it = it->next; + } + } + if (current_thread == th) current_thread = 0; + th->process->thread_count--; + kfree(th->kernelStack_addr); + kfree(th); +} + +/* Deletes a process. First, deletes all its threads. Also deletes the corresponding page directory. */ +static void process_delete(process *pr) { + thread *it = pr->threads; + while (it != 0) { + thread_delete(it); + it = it->next; + } + if (processes == pr) { + processes = pr->next; + } else { + process *it = processes; + while (it) { + if (it->next == pr) { + it->next = pr->next; + break; + } + it = it->next; + } + } + pagedir_delete(pr->pagedir); + kfree(pr); +} + +/* System call. Called by the app to define the place for the heap. */ +/*int process_setheapseg(size_t start, size_t end) { //syscall + struct process *p = current_thread->process; + if (start >= K_HIGHHALF_ADDR || end >= K_HIGHHALF_ADDR) return -1; + if (p->heapseg == 0) { + struct segment *s = simpleseg_make(start, end - start, 1); + if (s == 0) return -5; + p->heapseg = seg_map(s, p->pagedir, 0); + if (p->heapseg == 0) return -1; + return 0; + } else if (p->heapseg->start != start) { + seg_unmap(p->heapseg); + struct segment *s = simpleseg_make(start, end - start, 1); + if (s == 0) return -5; + p->heapseg = seg_map(s, p->pagedir, 0); + if (p->heapseg == 0) return -1; + return 0; + } else { + return simpleseg_resize(p->heapseg, end - start); + } +}*/ + +size_t process_sbrk(size_t size) { + process *p = current_thread->process; + if (p->data == 0) return -1; + ASSERT(p->data < K_HIGHHALF_ADDR); + if (p->data + size >= K_HIGHHALF_ADDR) return -1; + + size_t ret; + if (p->dataseg == 0) { + size_t start = p->data; + if (start & 0x0FFF) start = (start & 0xFFFFF000) + 0x1000; + size_t end = start + size; + if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; + + segment *s = simpleseg_make(start, end - start, 1); + if (s == 0) return -5; + p->dataseg = seg_map(s, p->pagedir, 0); + if (p->dataseg == 0) return -1; + + ret = start; + p->data = start + size; + } else { + size_t start = p->dataseg->start; + size_t end = p->data + size; + if (end <= start) return -1; + + if (end & 0x0FFF) end = (end & 0xFFFFF000) + 0x1000; + simpleseg_resize(p->dataseg, end - start); + + ret = p->data; + p->data += size; + } + /* (DBG) monitor_write("(sbrk "); + monitor_writeHex(size); + monitor_write(" "); + monitor_writeHex(ret); + monitor_write(")"); */ + return ret; +} + +void process_brk(size_t ptr) { + process *p = current_thread->process; + + ASSERT(ptr < K_HIGHHALF_ADDR); + process_sbrk(ptr - p->data); +} + diff --git a/src/kernel/task/task.h b/src/kernel/task/task.h index 63cb35a..47d7632 100644 --- a/src/kernel/task/task.h +++ b/src/kernel/task/task.h @@ -20,16 +20,17 @@ typedef void (*thread_entry)(void*); +struct thread; struct process { uint32_t pid, uid, privilege, thread_count; - struct process *parent; - struct page_directory *pagedir; + process *parent; + page_directory *pagedir; size_t stack, data; - struct segment_map *dataseg; + segment_map *dataseg; - struct process *next; //Forms a linked list - struct thread *threads; + process *next; //Forms a linked list + thread *threads; }; struct thread { @@ -40,21 +41,25 @@ struct thread { void* kernelStack_addr; uint32_t kernelStack_size; - struct thread *next, *queue_next; //queue_next is used in sched.c + thread *next, *queue_next; //queue_next is used in sched.c }; -extern struct thread *current_thread; +extern thread *current_thread; void tasking_init(); +#ifdef __cplusplus +extern "C" void schedule(); +#else void schedule(); -void tasking_updateKernelPagetable(uint32_t idx, struct page_table *table, uint32_t tablePhysical); -uint32_t tasking_handleException(struct registers *regs); +#endif +void tasking_updateKernelPagetable(uint32_t idx, page_table *table, uint32_t tablePhysical); +uint32_t tasking_handleException(registers *regs); void thread_goInactive(); //Blocks the current thread. it is then waked up by another thread or a system event. -void thread_wakeUp(struct thread *t); +void thread_wakeUp(thread *t); int proc_priv(); //Returns current privilege level -struct thread * thread_new(struct process *proc, thread_entry entry_point, void *data, void *u_esp); -struct process* process_new(struct process *parent, uint32_t uid, uint32_t privilege); +thread * thread_new(process *proc, thread_entry entry_point, void *data, void *u_esp); +process* process_new(process *parent, uint32_t uid, uint32_t privilege); void thread_exit(); //syscall void process_exit(size_t retval); //syscall diff --git a/src/kernel/task/timer.c b/src/kernel/task/timer.c deleted file mode 100644 index 35a94f9..0000000 --- a/src/kernel/task/timer.c +++ /dev/null @@ -1,91 +0,0 @@ -#include "timer.h" -#include "task.h" -#include "idt.h" -#include -#include -#include - -static uint32_t tick = 0, frequency = 0, uptime = 0; - -static void timer_callback(struct registers *regs); -static void timer_wakeUpSleepingThreads(); - -/* Called by kmain. Sets up the PIT and the IRQ0 handler. */ -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("[PIT] "); -} - -/* Accessor function to get machine uptime. */ -uint32_t timer_uptime() { return uptime; } - -/* Accessor function, gets uptime in miliseconds. */ -uint32_t timer_time() { - return (uptime * 1000) + (tick * 1000 / frequency); -} - -/* Called when IRQ0 fires. Updates the uptime variable. - DOES NOT provoke a task switch. The task switch is called in idt.c (IRQ handler). */ -void timer_callback(struct registers *regs) { - tick++; - if (tick == frequency) { - uptime++; - tick = 0; - } - timer_wakeUpSleepingThreads(); -} - -//************************************************ SLEEP FUNCTIONS ***************** - -static struct sleeping_thread { - uint32_t wakeup_time; - struct thread *thread; - struct sleeping_thread *next; -} *sleeping_threads = 0; - -/* Makes the current thread sleep. */ -void thread_sleep(uint32_t msecs) { - if (current_thread == 0) return; - // Create the sleeping_thread structure - struct sleeping_thread *sf = kmalloc(sizeof(struct sleeping_thread)), *tmp; - sf->wakeup_time = timer_time() + msecs; - sf->thread = current_thread; - //Insert it at the right place - if (sleeping_threads == 0 || sleeping_threads->wakeup_time >= sf->wakeup_time) { - sf->next = sleeping_threads; - sleeping_threads = sf; - } else { - tmp = sleeping_threads; - while (1) { - if (tmp->next == 0 || tmp->next->wakeup_time >= sf->wakeup_time) { - sf->next = tmp->next; - tmp->next = sf; - break; - } - tmp = tmp->next; - } - } - - thread_goInactive(); -} - -void timer_wakeUpSleepingThreads() { - uint32_t time = timer_time(); - while (sleeping_threads != 0 && sleeping_threads->wakeup_time <= time) { - struct sleeping_thread *tmp = sleeping_threads; - thread_wakeUp(tmp->thread); - sleeping_threads = tmp->next; - kfree(tmp); - } -} diff --git a/src/kernel/task/timer.cpp b/src/kernel/task/timer.cpp new file mode 100644 index 0000000..05c4550 --- /dev/null +++ b/src/kernel/task/timer.cpp @@ -0,0 +1,91 @@ +#include "timer.h" +#include "task.h" +#include "idt.h" +#include +#include +#include + +static uint32_t tick = 0, frequency = 0, uptime = 0; + +static void timer_callback(registers *regs); +static void timer_wakeUpSleepingThreads(); + +/* Called by kmain. Sets up the PIT and the IRQ0 handler. */ +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("[PIT] "); +} + +/* Accessor function to get machine uptime. */ +uint32_t timer_uptime() { return uptime; } + +/* Accessor function, gets uptime in miliseconds. */ +uint32_t timer_time() { + return (uptime * 1000) + (tick * 1000 / frequency); +} + +/* Called when IRQ0 fires. Updates the uptime variable. + DOES NOT provoke a task switch. The task switch is called in idt.c (IRQ handler). */ +void timer_callback(registers *regs) { + tick++; + if (tick == frequency) { + uptime++; + tick = 0; + } + timer_wakeUpSleepingThreads(); +} + +//************************************************ SLEEP FUNCTIONS ***************** + +static struct sleeping_thread { + uint32_t wakeup_time; + struct thread *thread; + sleeping_thread *next; +} *sleeping_threads = 0; + +/* Makes the current thread sleep. */ +void thread_sleep(uint32_t msecs) { + if (current_thread == 0) return; + // Create the sleeping_thread structure + sleeping_thread *sf = (sleeping_thread*)kmalloc(sizeof(sleeping_thread)), *tmp; + sf->wakeup_time = timer_time() + msecs; + sf->thread = current_thread; + //Insert it at the right place + if (sleeping_threads == 0 || sleeping_threads->wakeup_time >= sf->wakeup_time) { + sf->next = sleeping_threads; + sleeping_threads = sf; + } else { + tmp = sleeping_threads; + while (1) { + if (tmp->next == 0 || tmp->next->wakeup_time >= sf->wakeup_time) { + sf->next = tmp->next; + tmp->next = sf; + break; + } + tmp = tmp->next; + } + } + + thread_goInactive(); +} + +void timer_wakeUpSleepingThreads() { + uint32_t time = timer_time(); + while (sleeping_threads != 0 && sleeping_threads->wakeup_time <= time) { + sleeping_thread *tmp = sleeping_threads; + thread_wakeUp(tmp->thread); + sleeping_threads = tmp->next; + kfree(tmp); + } +} -- cgit v1.2.3