|
AquilaOS documentation
How it works, and its code
|
x86: keeping the CPUs' TLBs up to date when a mapping changes. More...
#include <core/system.h>#include <core/arch.h>#include <cpu/cpu.h>#include <mm/mm.h>#include <mm/pmap.h>#include <mm/vm.h>#include <platform/misc.h>#include <sys/cpu.h>#include <sys/lock.h>Go to the source code of this file.
Data Structures | |
| struct | [struct].request |
Macros | |
| #define | FLUSH_PAGES_MAX 32 |
| #define | ICR_ASSERT 0x4000 |
Functions | |
| static void | flush (vaddr_t sva, vaddr_t eva) |
| Flushes [sva, eva) from the running CPU's TLB. | |
| static void | request_do (struct pmap *pmap, vaddr_t sva, vaddr_t eva, int leave) |
| Does what a request asks of the running CPU: flush the range, if the CPU may have it, or switch away from page tables that are going away. | |
| void | x86_tlb_ipi (void) |
| Does the pending request if it is for the running CPU. | |
| void | arch_lock_spin (void) |
| Runs in the kernel lock's wait loop, on each turn. | |
| void | arch_lock_taken (void) |
| Runs once this CPU has taken the kernel lock. | |
| void | tlb_shootdown (struct pmap *pmap, vaddr_t sva, vaddr_t eva, int leave) |
| void | pmap_loaded (struct pmap *from, struct pmap *to) |
Variables | |
| static uint64_t | kernel_gen |
| static struct | request |
x86: keeping the CPUs' TLBs up to date when a mapping changes.
A CPU caches the mappings it uses in its TLB. When the page tables change (a page is unmapped, made read-only, or replaced), the CPU that changed them flushes its own TLB, asks the other CPUs that may have the old mapping to flush theirs with an IPI, and waits until they have. The page can't be reused while another CPU may still write to it.
For a process's page tables, the CPUs that may have the old mapping are those the tables are loaded on (pmap->cpus, which pmap_switch() keeps up to date). Only the CPU with the kernel lock changes page tables, so there is one request at a time. The other CPUs do it without the lock (someone else holds it): from the IPI's handler, or, if they are waiting for the lock with interrupts off, from that wait (arch_lock_spin()).
The kernel's mappings, shared by all page tables, are in every CPU's TLB, but the other CPUs aren't asked to flush them. Outside the lock, a CPU only touches memory that was mapped before it last took the lock, and that stays mapped while it uses it (its idle stack, its thread's kernel stack, its struct cpu, the lock, the page tables it has loaded). Instead, a CPU flushes its TLB when it takes the lock, if the kernel's mappings changed since it last did (kernel_gen).
Reloading CR3 flushes every mapping but the global ones. The only global pages are x86_64's direct map, which never changes.
Definition in file tlb.c.
| void arch_lock_spin | ( | void | ) |
Runs in the kernel lock's wait loop, on each turn.
The architecture answers the requests that the lock's holder makes of the other CPUs (a TLB flush), which can't wait until the lock is free.
Definition at line 101 of file tlb.c.
References arch_lock_spin(), and x86_tlb_ipi().
| void arch_lock_taken | ( | void | ) |
Runs once this CPU has taken the kernel lock.
The architecture catches up with what changed while it waited (the kernel's mappings).
Definition at line 109 of file tlb.c.
References cpu::arch, arch_lock_taken(), arch_cpu::kernel_gen, kernel_gen, and tlb_flush().
Flushes [sva, eva) from the running CPU's TLB.
Definition at line 60 of file tlb.c.
References flush(), FLUSH_PAGES_MAX, PAGE_SIZE, and tlb_flush().
Referenced by ata_sync(), flush(), and request_do().
Definition at line 160 of file tlb.c.
References pmap::cpus, and pmap_loaded().
Referenced by pmap_init(), pmap_loaded(), and pmap_switch().
Does what a request asks of the running CPU: flush the range, if the CPU may have it, or switch away from page tables that are going away.
Definition at line 73 of file tlb.c.
References flush(), kvm_space, vm_space::pmap, pmap_switch(), and request_do().
Referenced by request_do(), tlb_shootdown(), and x86_tlb_ipi().
Definition at line 124 of file tlb.c.
References arch_cpu::apic_id, cpu::arch, cpus, pmap::cpus, cpus_count, cur_pmap, ICR_ASSERT, k_pmap, kernel_gen, kvm_space, PAGE_SIZE, vm_space::pmap, pmap_switch(), request, request_do(), tlb_shootdown(), x86_lapic_ipi(), and X86_TLB_VECTOR.
Referenced by pmap_add(), pmap_protect(), pmap_release(), pmap_release(), pmap_release(), pmap_remove(), pmap_remove_all(), and tlb_shootdown().
| void x86_tlb_ipi | ( | void | ) |
Does the pending request if it is for the running CPU.
It is called from the TLB IPI's handler, and while waiting for the kernel lock.
Definition at line 87 of file tlb.c.
References request, request_do(), and x86_tlb_ipi().
Referenced by __x86_irq_handler(), arch_lock_spin(), and x86_tlb_ipi().
|
static |
Definition at line 48 of file tlb.c.
Referenced by arch_lock_taken(), and tlb_shootdown().
| struct [struct].request request |
Referenced by tlb_shootdown(), and x86_tlb_ipi().