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:
parent
ba28643e3e
commit
a7cb623747
7 changed files with 83 additions and 37 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue