1
0
Fork 0
mirror of https://github.com/hermitcore/libhermit.git synced 2025-03-09 00:00:03 +01:00

remove IPI for a TLB shootdown

HermitCore is an single address space operating system
=> a TLB shootdown isn't required
=> we have only to check if the page tables have an valid entry
=> if yes, flush TLB and return
=> if no, create a new page frame and map it into the address space
This commit is contained in:
Stefan Lankes 2016-01-04 16:27:19 +01:00
parent ba28643e3e
commit a7cb623747
7 changed files with 83 additions and 37 deletions

View file

@ -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
}

View file

@ -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);

View file

@ -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; vpn<start+npages; vpn++)
self[0][vpn] = 0;
spinlock_irqsave_unlock(&curr_task->page_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<PAGE_LEVELS; lvl++)
index[lvl] = vpn >> (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",

View file

@ -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

View file

@ -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;
}

View file

@ -37,13 +37,20 @@
#include <hermit/syscall.h>
#include <hermit/memory.h>
/*
* 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 */

View file

@ -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);
}