[kernel] Add a _very_ basic TLB shootdown mechanism

This TLB shootdown implementation is pretty janky: When the kernel
unmaps a mapping, it sends an IPI to all other cores and doesn't even
wait to ensure they've finished handling it. Upon getting one of these
IPIs, the core just re-writes cr3 to flush all TLBs.
This commit is contained in:
Justin C. Miller
2024-08-13 19:02:40 -07:00
parent d3c1d6cc34
commit 4649d5f77b
4 changed files with 28 additions and 10 deletions

View File

@@ -117,4 +117,5 @@ ISR (0xe1, 0, isrLINT0)
ISR (0xe2, 0, isrLINT1) ISR (0xe2, 0, isrLINT1)
ISR (0xe3, 0, isrAPICError) ISR (0xe3, 0, isrAPICError)
ISR (0xe4, 0, ipiSchedule) ISR (0xe4, 0, ipiSchedule)
ISR (0xe5, 0, ipiShootdown)

View File

@@ -21,6 +21,7 @@ constexpr uintptr_t apic_eoi_addr = 0xfee000b0 + mem::linear_offset;
extern "C" { extern "C" {
void isr_handler(cpu_state*); void isr_handler(cpu_state*);
void irq_handler(cpu_state*); void irq_handler(cpu_state*);
void _reload_cr3();
} }
uint8_t uint8_t
@@ -187,6 +188,11 @@ isr_handler(cpu_state *regs)
scheduler::get().schedule(); scheduler::get().schedule();
break; break;
case isr::ipiShootdown:
// TODO: Real shootdown algorithm
_reload_cr3();
break;
default: default:
util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt); util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt);
kassert(false, message, regs); kassert(false, message, regs);

View File

@@ -91,3 +91,10 @@ _current_gsbase:
mov rax, [gs:CPU_DATA.self] mov rax, [gs:CPU_DATA.self]
ret ret
.end: .end:
global _reload_cr3: function hidden (_reload_cr3.end - _reload_cr3)
_reload_cr3:
mov rax, cr3
mov cr3, rax
ret
.end:

View File

@@ -1,6 +1,7 @@
#include <j6/memutils.h> #include <j6/memutils.h>
#include <arch/memory.h> #include <arch/memory.h>
#include "apic.h"
#include "kassert.h" #include "kassert.h"
#include "frame_allocator.h" #include "frame_allocator.h"
#include "logger.h" #include "logger.h"
@@ -81,7 +82,7 @@ vm_space::kernel_space()
} }
uintptr_t uintptr_t
vm_space::add(uintptr_t base, obj::vm_area *area, util::bitset32 flags) vm_space::add(uintptr_t base, obj::vm_area *new_area, util::bitset32 flags)
{ {
if (!base) if (!base)
base = min_auto_address; base = min_auto_address;
@@ -89,23 +90,23 @@ vm_space::add(uintptr_t base, obj::vm_area *area, util::bitset32 flags)
//TODO: optimize find/insert //TODO: optimize find/insert
bool exact = flags.get(vm_flags::exact); bool exact = flags.get(vm_flags::exact);
for (size_t i = 0; i < m_areas.count(); ++i) { for (size_t i = 0; i < m_areas.count(); ++i) {
const vm_space::area &a = m_areas[i]; const vm_space::area &cur = m_areas[i];
uintptr_t aend = a.base + a.area->size(); uintptr_t cur_end = cur.base + cur.area->size();
if (base >= aend) if (base >= cur_end)
continue; continue;
uintptr_t end = base + area->size(); uintptr_t end = base + new_area->size();
if (end <= a.base) if (end <= cur.base)
break; break;
else if (exact) else if (exact)
return 0; return 0;
else else
base = aend; base = cur_end;
} }
m_areas.sorted_insert({base, area}); m_areas.sorted_insert({base, new_area});
area->add_to(this); new_area->add_to(this);
area->handle_retain(); new_area->handle_retain();
return base; return base;
} }
@@ -267,6 +268,9 @@ vm_space::clear(const obj::vm_area &vma, uintptr_t offset, size_t count, bool fr
++it; ++it;
} }
current_cpu().apic->send_ipi_broadcast(
lapic::ipi_fixed, false, isr::ipiShootdown);
if (free && free_count) if (free && free_count)
fa.free(free_start, free_count); fa.free(free_start, free_count);
} }