mmu: make shootdown data per cpu

This commit is contained in:
Matheus
2025-08-31 23:27:03 -03:00
parent 1c314b7098
commit 3f03b4a467
2 changed files with 21 additions and 16 deletions
+16 -16
View File
@@ -203,11 +203,6 @@ pagetableptr_t arch_mmu_newtable() {
return table; return table;
} }
static void *shootdown_page;
static size_t shootdown_size;
static spinlock_t shootdown_lock;
static int shootdown_remaining = 0;
static inline void do_invalidate(void *page, size_t size) { static inline void do_invalidate(void *page, size_t size) {
// if a full reload was requested or we are doing a big release on // if a full reload was requested or we are doing a big release on
if (page == NULL || size >= 32 * PAGE_SIZE) { if (page == NULL || size >= 32 * PAGE_SIZE) {
@@ -222,8 +217,10 @@ static inline void do_invalidate(void *page, size_t size) {
} }
void arch_mmu_tlbipi(isr_t *isr, context_t *context) { void arch_mmu_tlbipi(isr_t *isr, context_t *context) {
do_invalidate(shootdown_page, shootdown_size); do_invalidate(current_cpu()->shootdown_page, current_cpu()->shootdown_size);
__atomic_sub_fetch(&shootdown_remaining, 1, __ATOMIC_SEQ_CST); __assert(current_cpu()->shootdown_lock);
__atomic_add_fetch(current_cpu()->shootdown_done, 1, __ATOMIC_SEQ_CST);
spinlock_release(&current_cpu()->shootdown_lock);
} }
// if page == NULL, this will do a userspace shootdown that flushes the whole tlb // if page == NULL, this will do a userspace shootdown that flushes the whole tlb
@@ -238,30 +235,33 @@ void arch_mmu_invalidate_range(void *page, size_t size) {
|| ((page == NULL || (page >= USERSPACE_START && page < USERSPACE_END)) // or in userspace... || ((page == NULL || (page >= USERSPACE_START && page < USERSPACE_END)) // or in userspace...
&& thread->proc && thread->proc->runningthreadcount > 1)); // in a process which has multiple threads running && thread->proc && thread->proc->runningthreadcount > 1)); // in a process which has multiple threads running
int shootdown_done = 0;
int shootdown_total = 0;
int old_ipl; int old_ipl;
if (do_shootdown) { if (do_shootdown) {
old_ipl = interrupt_raiseipl(IPL_DPC); old_ipl = interrupt_raiseipl(IPL_DPC);
spinlock_acquire(&shootdown_lock);
shootdown_page = page;
shootdown_size = size;
shootdown_remaining = arch_smp_cpusawake - 1;
for (int i = 0; i < arch_smp_cpusawake; ++i) { for (int i = 0; i < arch_smp_cpusawake; ++i) {
if (smp_cpus[i] == current_cpu()) if (smp_cpus[i] == current_cpu())
continue; continue;
spinlock_acquire(&smp_cpus[i]->shootdown_lock);
smp_cpus[i]->shootdown_page = page;
smp_cpus[i]->shootdown_size = size;
smp_cpus[i]->shootdown_done = &shootdown_done;
++shootdown_total;
arch_smp_send_ipi(smp_cpus[i], &smp_cpus[i]->isr[0xfe], ARCH_SMP_IPI_TARGET, false); arch_smp_send_ipi(smp_cpus[i], &smp_cpus[i]->isr[0xfe], ARCH_SMP_IPI_TARGET, false);
} }
// we can lower ipl while waiting for the other cpus to shoot down because the spinlocks are now owned by the other cpus
interrupt_loweripl(old_ipl);
} }
do_invalidate(page, size); do_invalidate(page, size);
if (do_shootdown) { if (do_shootdown) {
while (__atomic_load_n(&shootdown_remaining, __ATOMIC_SEQ_CST)) CPU_PAUSE(); while (__atomic_load_n(&shootdown_done, __ATOMIC_SEQ_CST) != shootdown_total) CPU_PAUSE();
spinlock_release(&shootdown_lock);
interrupt_loweripl(old_ipl);
} }
} }
+5
View File
@@ -63,6 +63,11 @@ typedef struct cpu_t {
void *topology_node; void *topology_node;
void *shootdown_page;
size_t shootdown_size;
spinlock_t shootdown_lock;
int *shootdown_done;
// architecture specific, does not need to be exposed // architecture specific, does not need to be exposed
uint64_t gdt[7]; uint64_t gdt[7];