diff --git a/hermit/arch/x86/include/asm/processor.h b/hermit/arch/x86/include/asm/processor.h index b77e8fca0..142c5ced2 100644 --- a/hermit/arch/x86/include/asm/processor.h +++ b/hermit/arch/x86/include/asm/processor.h @@ -513,8 +513,10 @@ inline static void invalidate_cache(void) { asm volatile ("invd" ::: "memory"); } +#if 0 /// Send IPIs to the other core, which flush the TLB on the other cores. int ipi_tlb_flush(void); +#endif /** @brief Flush Translation Lookaside Buffer * @@ -528,7 +530,7 @@ static inline void flush_tlb(void) write_cr3(val); #if MAX_CORES > 1 - ipi_tlb_flush(); + //ipi_tlb_flush(); #endif } @@ -540,7 +542,7 @@ static inline void tlb_flush_one_page(size_t addr) asm volatile("invlpg (%0)" : : "r"(addr) : "memory"); #if MAX_CORES > 1 - ipi_tlb_flush(); + //ipi_tlb_flush(); #endif } diff --git a/hermit/arch/x86/kernel/apic.c b/hermit/arch/x86/kernel/apic.c index e4c64de9e..d3bf4d979 100644 --- a/hermit/arch/x86/kernel/apic.c +++ b/hermit/arch/x86/kernel/apic.c @@ -633,6 +633,7 @@ static inline void set_ipi_dest(uint32_t cpu_id) { lapic_write(APIC_ICR2, tmp); } +#if 0 int ipi_tlb_flush(void) { uint32_t id = CORE_ID; @@ -694,6 +695,7 @@ static void apic_tlb_handler(struct state *s) write_cr3(val); } #endif +#endif int apic_send_ipi(uint64_t dest, uint8_t irq) { @@ -771,7 +773,7 @@ int apic_init(void) // set APIC error handler irq_install_handler(126, apic_err_handler); #if MAX_CORES > 1 - irq_install_handler(80+32, apic_tlb_handler); + //irq_install_handler(80+32, apic_tlb_handler); #endif irq_install_handler(81+32, apic_shutdown); irq_install_handler(124, apic_lint0); diff --git a/hermit/arch/x86/mm/page.c b/hermit/arch/x86/mm/page.c index feff5f75d..ce2ec9273 100644 --- a/hermit/arch/x86/mm/page.c +++ b/hermit/arch/x86/mm/page.c @@ -121,7 +121,7 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) /** @todo: might not be sufficient! */ if (bits & PG_USER) - spinlock_irqsave_lock(&curr_task->page_lock); + spinlock_irqsave_lock(curr_task->page_lock); else spinlock_lock(&kslock); @@ -173,7 +173,7 @@ int page_map(size_t viraddr, size_t phyaddr, size_t npages, size_t bits) ret = 0; out: if (bits & PG_USER) - spinlock_irqsave_unlock(&curr_task->page_lock); + spinlock_irqsave_unlock(curr_task->page_lock); else spinlock_unlock(&kslock); @@ -187,7 +187,7 @@ int page_unmap(size_t viraddr, size_t npages) /* We aquire both locks for kernel and task tables * as we dont know to which the region belongs. */ - spinlock_irqsave_lock(&curr_task->page_lock); + spinlock_irqsave_lock(curr_task->page_lock); spinlock_lock(&kslock); /* Start iterating through the entries. @@ -196,7 +196,7 @@ int page_unmap(size_t viraddr, size_t npages) for (vpn=start; vpnpage_lock); + spinlock_irqsave_unlock(curr_task->page_lock); spinlock_unlock(&kslock); /* This can't fail because we don't make checks here */ @@ -221,11 +221,11 @@ int page_map_drop(void) } } - spinlock_irqsave_lock(&curr_task->page_lock); + spinlock_irqsave_lock(curr_task->page_lock); traverse(PAGE_LEVELS-1, 0); - spinlock_irqsave_unlock(&curr_task->page_lock); + spinlock_irqsave_unlock(curr_task->page_lock); /* This can't fail because we don't make checks here */ return 0; @@ -268,14 +268,14 @@ int page_map_copy(task_t *dest) // set present bit dest->page_map |= PG_PRESENT; - spinlock_irqsave_lock(&curr_task->page_lock); + spinlock_irqsave_lock(curr_task->page_lock); self[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = dest->page_map | PG_PRESENT | PG_SELF | PG_RW; int ret = traverse(PAGE_LEVELS-1, 0); other[PAGE_LEVELS-1][PAGE_MAP_ENTRIES-1] = dest->page_map | PG_PRESENT | PG_SELF | PG_RW; self [PAGE_LEVELS-1][PAGE_MAP_ENTRIES-2] = 0; - spinlock_irqsave_unlock(&curr_task->page_lock); + spinlock_irqsave_unlock(curr_task->page_lock); /* Flush TLB entries of 'other' self-reference */ flush_tlb(); @@ -288,9 +288,40 @@ void page_fault_handler(struct state *s) size_t viraddr = read_cr2(); task_t* task = per_core(current_task); - if ((task->heap) && (viraddr >= task->heap->start) && (viraddr < task->heap->end)) { - // on demand userspace heap mapping + int check_pagetables(size_t vaddr) + { + int lvl; + long vpn = vaddr >> PAGE_BITS; + long index[PAGE_LEVELS]; + /* Calculate index boundaries for page map traversal */ + for (lvl=0; lvl> (lvl * PAGE_MAP_BITS); + + /* do we have already a valid entry in the page tables */ + for (lvl=PAGE_LEVELS-1; lvl>=0; lvl--) { + vpn = index[lvl]; + + if (!(self[lvl][vpn] & PG_PRESENT)) + return 0; + } + + return 1; + } + + spinlock_irqsave_lock(task->page_lock); + + if ((task->heap) && (viraddr >= task->heap->start) && (viraddr < task->heap->end)) { + /* + * do we have a valid page table entry? => flush TLB and return + */ + if (check_pagetables(viraddr)) { + tlb_flush_one_page(viraddr); + spinlock_irqsave_unlock(task->page_lock); + return; + } + + // on demand userspace heap mapping viraddr &= PAGE_MASK; size_t phyaddr = get_page(); @@ -309,10 +340,14 @@ void page_fault_handler(struct state *s) memset((void*) viraddr, 0x00, PAGE_SIZE); // fill with zeros + spinlock_irqsave_unlock(task->page_lock); + return; } default_handler: + spinlock_irqsave_unlock(task->page_lock); + kprintf("Page Fault Exception (%d) on core %d at cs:ip = %#x:%#lx, fs = %#lx, gs = %#lx, rflags 0x%lx, task = %u, addr = %#lx, error = %#x [ %s %s %s %s %s ]\n", s->int_no, CORE_ID, s->cs, s->rip, s->fs, s->gs, s->rflags, task->id, viraddr, s->error, (s->error & 0x4) ? "user" : "supervisor", diff --git a/hermit/include/hermit/tasks_types.h b/hermit/include/hermit/tasks_types.h index ef2823a33..59c563185 100644 --- a/hermit/include/hermit/tasks_types.h +++ b/hermit/include/hermit/tasks_types.h @@ -89,9 +89,9 @@ typedef struct task { /// Physical address of root page table size_t page_map; /// Lock for page tables - spinlock_irqsave_t page_lock; + spinlock_irqsave_t* page_lock; /// lock for the VMA_list - spinlock_t vma_lock; + spinlock_t* vma_lock; /// list of VMAs vma_t* vma_list; /// starting time/tick of the task diff --git a/hermit/kernel/syscall.c b/hermit/kernel/syscall.c index 9e759800d..8589c83c4 100644 --- a/hermit/kernel/syscall.c +++ b/hermit/kernel/syscall.c @@ -194,7 +194,7 @@ ssize_t sys_sbrk(int incr) vma_t* heap = task->heap; ssize_t ret; - spinlock_lock(&task->vma_lock); + spinlock_lock(task->vma_lock); if (BUILTIN_EXPECT(!heap, 0)) { kprintf("sys_sbrk: missing heap!\n"); @@ -209,7 +209,7 @@ ssize_t sys_sbrk(int incr) // allocation and mapping of new pages for the heap // is catched by the pagefault handler - spinlock_unlock(&task->vma_lock); + spinlock_unlock(task->vma_lock); return ret; } diff --git a/hermit/kernel/tasks.c b/hermit/kernel/tasks.c index 1b546bcf1..a23329898 100644 --- a/hermit/kernel/tasks.c +++ b/hermit/kernel/tasks.c @@ -37,13 +37,20 @@ #include #include +/* + * HermitCore is a single address space OS + * => we need only a lock to protect the page tables & VMA + */ +static spinlock_irqsave_t page_lock = SPINLOCK_IRQSAVE_INIT; +static spinlock_t vma_lock = SPINLOCK_INIT; + /** @brief Array of task structures (aka PCB) * * A task's id will be its position in this array. */ static task_t task_table[MAX_TASKS] = { \ - [0] = {0, TASK_IDLE, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0}, \ - [1 ... MAX_TASKS-1] = {0, TASK_INVALID, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, SPINLOCK_IRQSAVE_INIT, SPINLOCK_INIT, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0}}; + [0] = {0, TASK_IDLE, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, &page_lock, &vma_lock, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0}, \ + [1 ... MAX_TASKS-1] = {0, TASK_INVALID, 0, NULL, NULL, TASK_DEFAULT_FLAGS, 0, 0, 0, &page_lock, &vma_lock, NULL, 0, NULL, NULL, 0, NULL, NULL, 0, 0, 0}}; static spinlock_irqsave_t table_lock = SPINLOCK_IRQSAVE_INIT; @@ -148,10 +155,10 @@ int set_idle_task(void) task_table[i].stack = (char*) ((size_t)&boot_stack + core_id * KERNEL_STACK_SIZE); set_per_core(kernel_stack, task_table[i].stack + KERNEL_STACK_SIZE - 0x10); task_table[i].prio = IDLE_PRIO; - spinlock_init(&task_table[i].vma_lock); + task_table[i].vma_lock = &vma_lock; task_table[i].vma_list = NULL; task_table[i].heap = NULL; - spinlock_irqsave_init(&task_table[i].page_lock); + task_table[i].page_lock = &page_lock; task_table[i].user_usage = NULL; task_table[i].page_map = read_cr3(); readyqueues[core_id].idle = task_table+i; @@ -415,7 +422,7 @@ int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uint32_t c task_table[i].last_stack_pointer = NULL; task_table[i].stack = stack; task_table[i].prio = prio; - spinlock_init(&task_table[i].vma_lock); + task_table[i].vma_lock = &vma_lock; task_table[i].vma_list = NULL; task_table[i].heap = NULL; task_table[i].start_tick = get_clock_tick(); @@ -424,7 +431,7 @@ int create_task(tid_t* id, entry_point_t ep, void* arg, uint8_t prio, uint32_t c task_table[i].tls_size = 0; task_table[i].lwip_err = 0; - spinlock_irqsave_init(&task_table[i].page_lock); + task_table[i].page_lock = &page_lock; task_table[i].user_usage = (atomic_int64_t*) counter; /* Allocated new PGD or PML4 and copy page table */ diff --git a/hermit/mm/vma.c b/hermit/mm/vma.c index 0f3e44986..10d5a4bd6 100644 --- a/hermit/mm/vma.c +++ b/hermit/mm/vma.c @@ -88,7 +88,7 @@ size_t vma_alloc(size_t size, uint32_t flags) base = VMA_USER_MIN; limit = VMA_USER_MAX; list = &task->vma_list; - lock = &task->vma_lock; + lock = task->vma_lock; } else { base = VMA_KERN_MIN; @@ -163,7 +163,7 @@ int vma_free(size_t start, size_t end) list = &vma_list; } else if (start >= VMA_KERN_MAX) { - lock = &task->vma_lock; + lock = task->vma_lock; list = &task->vma_list; } @@ -230,7 +230,7 @@ int vma_add(size_t start, size_t end, uint32_t flags) if (flags & VMA_USER) { list = &task->vma_list; - lock = &task->vma_lock; + lock = task->vma_lock; // check if address is in userspace if (BUILTIN_EXPECT(start < VMA_KERN_MAX, 0)) @@ -294,18 +294,18 @@ int vma_add(size_t start, size_t end, uint32_t flags) int copy_vma_list(task_t* src, task_t* dest) { - spinlock_init(&dest->vma_lock); + spinlock_init(dest->vma_lock); - spinlock_lock(&src->vma_lock); - spinlock_lock(&dest->vma_lock); + spinlock_lock(src->vma_lock); + spinlock_lock(dest->vma_lock); vma_t* last = NULL; vma_t* old; for (old=src->vma_list; old; old=old->next) { vma_t *new = kmalloc(sizeof(vma_t)); if (BUILTIN_EXPECT(!new, 0)) { - spinlock_unlock(&dest->vma_lock); - spinlock_unlock(&src->vma_lock); + spinlock_unlock(dest->vma_lock); + spinlock_unlock(src->vma_lock); return -ENOMEM; } @@ -322,8 +322,8 @@ int copy_vma_list(task_t* src, task_t* dest) last = new; } - spinlock_unlock(&dest->vma_lock); - spinlock_unlock(&src->vma_lock); + spinlock_unlock(dest->vma_lock); + spinlock_unlock(src->vma_lock); return 0; } @@ -332,14 +332,14 @@ int drop_vma_list(task_t *task) { vma_t* vma; - spinlock_lock(&task->vma_lock); + spinlock_lock(task->vma_lock); while ((vma = task->vma_list)) { task->vma_list = vma->next; kfree(vma); } - spinlock_unlock(&task->vma_lock); + spinlock_unlock(task->vma_lock); return 0; } @@ -364,7 +364,7 @@ void vma_dump(void) spinlock_unlock(&vma_lock); kputs("Userspace VMAs:\n"); - spinlock_lock(&task->vma_lock); + spinlock_lock(task->vma_lock); print_vma(task->vma_list); - spinlock_unlock(&task->vma_lock); + spinlock_unlock(task->vma_lock); }