diff --git a/arch/x86/kernel/isrs.c b/arch/x86/kernel/isrs.c index 6df9526e..cfb45389 100644 --- a/arch/x86/kernel/isrs.c +++ b/arch/x86/kernel/isrs.c @@ -169,13 +169,16 @@ static void fpu_handler(struct state *s) { task_t* task = per_core(current_task); - kputs("got FPU exception\n"); asm volatile ("clts"); // clear the TS flag of cr0 - if (!task->fpu_used) { - task->fpu_used = 1; + if (!(task->flags & TASK_FPU_INIT)) { + // use the FPU at the first time => Initialize FPU asm volatile ("finit"); - } else + task->flags = task->flags|TASK_FPU_INIT|TASK_FPU_USED; + } else { + // restore the FPU context asm volatile ("frstor %0" :: "m"(task->fpu.fsave)); // restore fpu state + task->flags |= TASK_FPU_USED; + } } /** @brief Exception messages diff --git a/arch/x86/mm/page.c b/arch/x86/mm/page.c index 4e5c4f7c..75f34015 100644 --- a/arch/x86/mm/page.c +++ b/arch/x86/mm/page.c @@ -588,7 +588,28 @@ int print_paging_tree(size_t viraddr) static void pagefault_handler(struct state *s) { - kprintf("PAGE FAULT: Task %u got page fault at %p (irq %d)\n", per_core(current_task)->id, read_cr2(), s->int_no); + task_t* task = per_core(current_task); + size_t viraddr = read_cr2(); + size_t phyaddr; + + if ((viraddr >= task->start_heap) && (viraddr <= task->end_heap) && (viraddr > KERNEL_SPACE)) { + viraddr = viraddr & 0xFFFFF000; + + phyaddr = get_page(); + if (BUILTIN_EXPECT(!phyaddr, 0)) + goto default_handler; + + if (map_region(viraddr, phyaddr, 1, MAP_USER_SPACE|MAP_HEAP) == viraddr) { + memset((void*) viraddr, 0x00, PAGE_SIZE); + return; + } + + kprintf("Could not map 0x%x at 0x%x\n", phyaddr, viraddr); + put_page(phyaddr); + } + +default_handler: + kprintf("PAGE FAULT: Task %u got page fault at %p (irq %d)\n", task->id, viraddr, s->int_no); kprintf("Register state: eax = 0x%x, ebx = 0x%x, ecx = 0x%x, edx = 0x%x, edi = 0x%x, esi = 0x%x, ebp = 0x%x, esp = 0x%x\n", s->eax, s->ebx, s->ecx, s->edx, s->edi, s->esi, s->ebp, s->esp); diff --git a/include/metalsvm/tasks_types.h b/include/metalsvm/tasks_types.h index c46ec4b4..58f65cf2 100644 --- a/include/metalsvm/tasks_types.h +++ b/include/metalsvm/tasks_types.h @@ -47,6 +47,10 @@ extern "C" { #define TASK_FINISHED 4 #define TASK_IDLE 5 +#define TASK_DEFAULT_FLAGS 0 +#define TASK_FPU_INIT (1 << 0) +#define TASK_FPU_USED (1 << 1) + typedef int (STDCALL *entry_point_t)(void*); struct page_dir; @@ -66,8 +70,12 @@ typedef struct task { spinlock_t vma_lock; /// List of VMAs vma_t* vma_list; - /// Is set, when the FPU is used - uint32_t fpu_used; + /// Additional status flags. For instance, to signalize the using of the FPU + uint32_t flags; + /// Start address of the heap + uint32_t start_heap; + /// End address of the heap + uint32_t end_heap; /// Mail inbox mailbox_wait_msg_t inbox; /// Mail outbox array diff --git a/kernel/syscall.c b/kernel/syscall.c index 76ce8e10..95a39fc6 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -22,6 +22,7 @@ #include #include #include +#include static int sys_write(int fildes, const char *buf, size_t len) { @@ -37,6 +38,32 @@ static int sys_write(int fildes, const char *buf, size_t len) return len; } +static int sys_sbrk(int incr) +{ + task_t* task = per_core(current_task); + vma_t* tmp = NULL; + int ret; + + spinlock_lock(&task->vma_lock); + + tmp = task->vma_list; + while(tmp && !((task->end_heap >= tmp->start) && (task->end_heap <= tmp->end))) + tmp = tmp->next; + + ret = (int) task->end_heap; + task->end_heap += incr; + if (task->end_heap < task->start_heap) + task->end_heap = task->start_heap; + + // resize virtual memory area + if (tmp && (tmp->end <= task->end_heap)) + tmp->end = task->end_heap; + + spinlock_unlock(&task->vma_lock); + + return ret; +} + int syscall_handler(uint32_t sys_nr, ...) { int ret = -EINVAL; @@ -64,6 +91,12 @@ int syscall_handler(uint32_t sys_nr, ...) case __NR_close: ret = 0; break; + case __NR_sbrk: { + int incr = va_arg(vl, int); + + ret = sys_sbrk(incr); + break; + } case __NR_getpid: ret = per_core(current_task)->id; break; diff --git a/kernel/tasks.c b/kernel/tasks.c index 3ffb49b9..ae699687 100644 --- a/kernel/tasks.c +++ b/kernel/tasks.c @@ -48,7 +48,7 @@ DEFINE_PER_CORE(task_t*, current_task, NULL); * A task's id will be its position in this array. */ static task_t task_table[MAX_TASKS] = {[0 ... MAX_TASKS-1] = {0, TASK_INVALID, ATOMIC_INIT(0), \ - SPINLOCK_INIT, NULL, SPINLOCK_INIT, NULL, 0}}; + SPINLOCK_INIT, NULL, SPINLOCK_INIT, NULL, 0, 0, 0}}; static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT; /** @brief helper function for the assembly code to determine the current task @@ -67,7 +67,7 @@ int multitasking_init(void) { memset(task_table[0].outbox, 0x00, sizeof(mailbox_wait_msg_t*)*MAX_TASKS); per_core(current_task) = task_table+0; per_core(current_task)->pgd = get_boot_pgd(); - task_table[0].fpu_used = 0; + task_table[0].flags = TASK_DEFAULT_FLAGS; return 0; } @@ -190,7 +190,9 @@ static int create_task(tid_t* id, entry_point_t ep, void* arg) ret = create_default_frame(task_table+i, ep, arg); - task_table[i].fpu_used = 0; + task_table[i].flags = TASK_DEFAULT_FLAGS; + task_table[i].start_heap = 0; + task_table[i].end_heap = 0; task_table[i].status = TASK_READY; break; } @@ -252,7 +254,10 @@ int sys_fork(void) mailbox_wait_msg_init(&task_table[i].inbox); memset(task_table[i].outbox, 0x00, sizeof(mailbox_wait_msg_t*)*MAX_TASKS); task_table[i].outbox[per_core(current_task)->id] = &per_core(current_task)->inbox; - task_table[i].fpu_used = 0x00; + task_table[i].flags = per_core(current_task)->flags; + memcpy(&(task_table[i].fpu), &(per_core(current_task)->fpu), sizeof(union fpu_state)); + task_table[i].start_heap = 0; + task_table[i].end_heap = 0; ret = arch_fork(task_table+i); @@ -352,8 +357,8 @@ static int load_task(load_args_t* largs) if (!prog_header.virt_addr) continue; - npages = (prog_header.mem_size / PAGE_SIZE); - if (prog_header.mem_size % PAGE_SIZE) + npages = (prog_header.mem_size >> PAGE_SHIFT); + if (prog_header.mem_size & (PAGE_SIZE-1)) npages++; addr = get_pages(npages); @@ -369,6 +374,10 @@ static int load_task(load_args_t* largs) // clear pages memset((void*) prog_header.virt_addr, 0, npages*PAGE_SIZE); + // set starting point of the heap + if (per_core(current_task)->start_heap < prog_header.virt_addr+prog_header.mem_size) + per_core(current_task)->start_heap = per_core(current_task)->end_heap = prog_header.virt_addr+prog_header.mem_size; + // load program read_fs(node, (uint8_t*)prog_header.virt_addr, prog_header.file_size, prog_header.offset); @@ -387,8 +396,8 @@ static int load_task(load_args_t* largs) case ELF_PT_GNU_STACK: // Indicates stack executability // create user-level stack - npages = DEFAULT_STACK_SIZE / PAGE_SIZE; - if (DEFAULT_STACK_SIZE % PAGE_SIZE) + npages = DEFAULT_STACK_SIZE >> PAGE_SHIFT; + if (DEFAULT_STACK_SIZE & (PAGE_SIZE-1)) npages++; addr = get_pages(npages); @@ -475,6 +484,9 @@ static int load_task(load_args_t* largs) kfree(largs, sizeof(load_args_t)); + // clear fpu state + per_core(current_task)->flags &= ~(TASK_FPU_USED|TASK_FPU_INIT); + jump_to_user_code(header.entry, stack+offset); return 0; @@ -703,6 +715,12 @@ void scheduler(void) if (per_core(current_task)->status == TASK_FINISHED) per_core(current_task)->status = TASK_INVALID; + /* if the task is using the FPU, we need to save the FPU context */ + if (per_core(current_task)->flags & TASK_FPU_USED) { + save_fpu_state(&(per_core(current_task)->fpu)); + per_core(current_task)->flags &= ~TASK_FPU_USED; + } + for(i=1, new_id=(per_core(current_task)->id + 1) % MAX_TASKS; istatus == TASK_RUNNING) per_core(current_task)->status = TASK_READY; task_table[new_id].status = TASK_RUNNING; - - if (per_core(current_task)->fpu_used) - save_fpu_state(&(per_core(current_task)->fpu)); per_core(current_task) = task_table+new_id; + goto get_task_out; } } diff --git a/kernel/tests.c b/kernel/tests.c index fe26ffc6..08f3d45f 100644 --- a/kernel/tests.c +++ b/kernel/tests.c @@ -114,6 +114,7 @@ int test_init(void) //create_kernel_task(NULL, consumer, NULL); //create_user_task(NULL, "/bin/hello", argv); create_user_task(NULL, "/bin/tests", argv); + //create_user_task(NULL, "/bin/jacobi", argv); return 0; } diff --git a/newlib/src/libgloss/metalsvm/sbrk.c b/newlib/src/libgloss/metalsvm/sbrk.c index 356c5ee7..78002469 100644 --- a/newlib/src/libgloss/metalsvm/sbrk.c +++ b/newlib/src/libgloss/metalsvm/sbrk.c @@ -22,23 +22,20 @@ #include #undef errno extern int errno; +#include "warning.h" +#include "syscall.h" -#ifndef NULL -#define NULL ((void*) 0) -#endif +void* +_DEFUN (sbrk, (incr), + int incr) +{ + int ret; -void * -sbrk (incr) - int incr; -{ - extern char _end; // set by linker - static char *heap_end = NULL; - char *prev_heap_end; + ret = SYSCALL1(__NR_sbrk, incr); + if (ret < 0x1000) { + errno = -ret; + ret = -1; + } - if (!heap_end) - heap_end = &_end; - prev_heap_end = heap_end; - heap_end += incr; - - return (void *) prev_heap_end; + return (void*) ret; }